home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / rpg / crossfir.92 / crossfir / crossfire-0.92.5 / server / spell_effect.c < prev    next >
C/C++ Source or Header  |  1996-07-24  |  86KB  |  2,811 lines

  1. /*
  2.  * static char *rcsid_newspells_c =
  3.  *   "$Id: spell_effect.c,v 1.12 1996/07/24 07:42:42 master Exp master $";
  4.  */
  5.  
  6.  
  7. /*
  8.     CrossFire, A Multiplayer game for X-windows
  9.  
  10.     Copyright (C) 1992 Frank Tore Johansen
  11.  
  12.     This program is free software; you can redistribute it and/or modify
  13.     it under the terms of the GNU General Public License as published by
  14.     the Free Software Foundation; either version 2 of the License, or
  15.     (at your option) any later version.
  16.  
  17.     This program is distributed in the hope that it will be useful,
  18.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.     GNU General Public License for more details.
  21.  
  22.     You should have received a copy of the GNU General Public License
  23.     along with this program; if not, write to the Free Software
  24.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26.     The author can be reached via e-mail to frankj@ifi.uio.no.
  27. */
  28.  
  29. #include <global.h>
  30. #include <object.h>
  31. #include <living.h>
  32. #ifndef __CEXTRACT__
  33. #include <sproto.h>
  34. #endif
  35. #include <spells.h>
  36. #ifdef SOUND_EFFECTS
  37. #include <sounds.h>
  38. #endif
  39.  
  40. extern object *objects;
  41.  
  42. /* 
  43.  * spell_failure()  handles the various effects for differing degrees
  44.  * of failure badness.
  45.  */
  46. #ifdef SPELL_FAILURE_EFFECTS
  47. void spell_failure(object *op, int failure,int power)
  48. {  
  49.   if(failure<= -20&&failure > -40) /* wonder */
  50.     {
  51.      new_draw_info(NDI_UNIQUE, 0,op,"Your spell causes an unexpected effect.");
  52.      cast_cone(op,0,10,SP_WOW,spellarch[SP_WOW],0);
  53.     }
  54.  
  55.   else if (failure <= -40&&failure > -60) /* confusion */
  56.    {
  57.     new_draw_info(NDI_UNIQUE, 0,op,"Your magic recoils on you!");
  58.     confuse_player(op,op,99);
  59.    }
  60.   else if (failure <= -60&&failure> -80) /* paralysis */
  61.   {
  62.     new_draw_info(NDI_UNIQUE, 0,op,"Your magic recoils on you!");
  63.     paralyze_player(op,op,99);
  64.   }
  65.   else if (failure <= -80) /* blast the immediate area */
  66.   { object *tmp;
  67.    new_draw_info(NDI_UNIQUE, 0,op,"You lose control of the mana!  The uncontrolled magic blasts you!");
  68.    tmp=get_archetype("loose_magic");
  69.    
  70. /*
  71.    tmp->level=op->level;
  72.  */
  73.    tmp->level=SK_level(op);
  74.    tmp->x=op->x;tmp->y=op->y;
  75.    tmp->stats.hp+=power/5;  /* increase the area of destruction a little for more powerful spells */
  76.    tmp->stats.dam=power; /* nasty recoils! */
  77.    tmp->stats.maxhp=tmp->count; /*??*/
  78.    insert_ob_in_map(tmp,op->map);
  79.   }
  80. }
  81. #endif
  82.  
  83. /* Oct 95 - hacked on this to bring in cosmetic differences for MULTIPLE_GOD hack -b.t. */
  84.  
  85. void prayer_failure(object *op, int failure,int power)
  86. {  
  87. #ifdef MULTIPLE_GODS 
  88.   char *godname;
  89.  
  90.   if(!strcmp((godname=determine_god(op)),"none")) godname="Your spirit";
  91. #endif 
  92.  
  93.   if(failure<= -20&&failure > -40) /* wonder */
  94.     {
  95. #ifdef MULTIPLE_GODS 
  96.      new_draw_info_format(NDI_UNIQUE, 0,op,"%s gives a sign to renew your faith.",godname);
  97. #else
  98.      new_draw_info(NDI_UNIQUE, 0,op,"God gives a sign to renew your faith.");
  99. #endif
  100.      cast_cone(op,0,10,SP_WOW,spellarch[SP_WOW],0);
  101.     }
  102.  
  103.   else if (failure <= -40&&failure > -60) /* confusion */
  104.    {
  105.     new_draw_info(NDI_UNIQUE, 0,op,"Your diety touches your mind!");
  106.     confuse_player(op,op,99);
  107.    }
  108.   else if (failure <= -60&&failure> -80) /* paralysis */
  109.   {
  110. #ifdef MULTIPLE_GODS
  111.     new_draw_info_format(NDI_UNIQUE, 0,op,"%s requires you to pray NOW.",godname);
  112. #else
  113.     new_draw_info(NDI_UNIQUE, 0,op,"Your god requires you to pray NOW.");
  114. #endif
  115.      new_draw_info(NDI_UNIQUE, 0,op,"You comply, ignoring all else.");
  116.     paralyze_player(op,op,99);
  117.   }
  118.   else if (failure <= -80) /* blast the immediate area */
  119.   { 
  120. #ifdef MULTIPLE_GODS
  121.    new_draw_info_format(NDI_UNIQUE, 0,op,"%s smites you!",godname);
  122. #else
  123.    new_draw_info(NDI_UNIQUE, 0,op,"God smites you!");
  124. #endif
  125.    
  126.    cast_mana_storm(op,power);
  127.  
  128.   }
  129. }
  130.     
  131. void cast_mana_storm(object *op, int lvl) {
  132.   object *tmp=get_archetype("loose_magic"); 
  133.  
  134.     tmp->level=SK_level(op);
  135.     tmp->x=op->x;tmp->y=op->y; 
  136.     tmp->stats.hp+=lvl/5;  /* increase the area of destruction */
  137.     tmp->stats.dam=lvl; /* nasty recoils! */ 
  138.     tmp->stats.maxhp=tmp->count; /*??*/ 
  139.     insert_ob_in_map(tmp,op->map); 
  140.  
  141. }
  142.  
  143. void aggravate_monsters(object *op) {
  144.   int i,j;
  145.   object *tmp;
  146.  
  147.   spell_effect(SP_AGGRAVATION, op->x, op->y, op->map);
  148.  
  149.   for (i = 0; i < op->map->mapx; i++)
  150.     for (j = 0; j < op->map->mapy; j++) {
  151.       if (out_of_map(op->map, op->x + i , op->y + j))
  152.         continue;
  153.       for (tmp = get_map_ob(op->map, op->x + i, op->y + j);
  154.            tmp; tmp = tmp->above)
  155.         if (QUERY_FLAG(tmp, FLAG_MONSTER)) {
  156.       CLEAR_FLAG(tmp, FLAG_SLEEP);
  157.           if (!QUERY_FLAG(tmp, FLAG_FRIENDLY))
  158.             tmp->enemy = op;
  159.         }
  160.     }
  161. }
  162.  
  163.  
  164. int recharge(object *op) {
  165.   object *wand;
  166.  
  167.   for(wand = op->inv; wand != NULL; wand = wand->below)
  168.     if(wand->type == WAND && QUERY_FLAG(wand, FLAG_APPLIED))
  169.       break;
  170.   if(wand == NULL)
  171.     return 0;
  172.   if(!(RANDOM()%4)) {
  173.     new_draw_info_format(NDI_UNIQUE, 0, op,
  174.     "The %s vibrates violently, then explodes!",query_name(wand));
  175. #ifdef SOUND_EFFECTS
  176.     play_sound_map(op->map, op->x, op->y, SOUND_OB_EXPLODE);
  177. #endif
  178.     spell_effect(SP_DESTRUCTION, op->x, op->y, op->map);
  179.     remove_ob(wand);
  180.     free_object(wand);
  181.     return 1;
  182.   }
  183.   new_draw_info_format(NDI_UNIQUE, 0, op,
  184.     "The %s glows with power.",query_name(wand));
  185.  
  186.   wand->stats.food += RANDOM()%spells[wand->stats.sp].charges + 1;
  187.   if(wand->arch&&QUERY_FLAG(&wand->arch->clone, FLAG_ANIMATE))
  188.   {
  189.     SET_FLAG(wand, FLAG_ANIMATE);
  190.     wand->speed = wand->arch->clone.speed;
  191.     update_ob_speed(wand);
  192.   }
  193.   return 1;
  194. }
  195.  
  196. #define MAX_ALT 80
  197.  
  198. void polymorph_living(object *op) {
  199.   archetype *altern[MAX_ALT], *at;
  200.   int nr = 0, x = op->x, y = op->y, choice, friendly;
  201.   mapstruct *map = op->map;
  202.   object *tmp, *next, *owner;
  203.  
  204.   if(op->head != NULL || op->more != NULL)
  205.     return;
  206.   for(at = first_archetype ; at != NULL; at = at->next)
  207.     if(QUERY_FLAG((&at->clone),FLAG_MONSTER) == QUERY_FLAG(op, FLAG_MONSTER) &&
  208.        QUERY_FLAG((&at->clone),FLAG_GENERATOR) == QUERY_FLAG(op,FLAG_GENERATOR) &&
  209.        at->more == NULL && EDITABLE((&at->clone)))
  210.     {
  211.       altern[nr] = at;
  212.       if(++nr == MAX_ALT)
  213.         break;
  214.     }
  215.   if(!nr)
  216.     return;
  217.   choice = RANDOM()%nr;
  218.   for(tmp = op->inv; tmp != NULL; tmp = next) {
  219.     next = tmp->below;
  220.     if(QUERY_FLAG(tmp, FLAG_APPLIED))
  221.       apply(op,tmp);
  222.     if(tmp->type == ABILITY) {
  223.       remove_ob(tmp);
  224.       free_object(tmp);
  225.     }
  226.   }
  227.   remove_ob(op);
  228.   owner = get_owner(op);
  229.   friendly = QUERY_FLAG(op, FLAG_FRIENDLY);
  230.   if (friendly)
  231.     remove_friendly_object(op);
  232.   copy_object(&(altern[choice]->clone),op);
  233.   if (owner != NULL)
  234.     set_owner(op,owner);
  235.   if (friendly) {
  236.     SET_FLAG(op, FLAG_FRIENDLY);
  237.     op->move_type = PETMOVE;
  238.     add_friendly_object(op);
  239.   }
  240.   op->x = x; op->y = y;
  241.   insert_ob_in_map(op,map);
  242.   update_object(op);
  243.   if(op->arch->randomitems != NULL)
  244.     create_treasure(op->arch->randomitems,op,GT_INVISIBLE,map->difficulty,0);
  245.   for(tmp = op->inv, nr = 0; tmp != NULL && ++nr < 20; tmp = next) {
  246.     next = tmp->below;
  247.     (void) monster_check_apply(op,tmp);
  248.   }
  249. }
  250.  
  251.  
  252. /* Destroys item from polymorph failure */
  253. void polymorph_melt(object *who, object *op)
  254. {
  255.  
  256.     new_draw_info_format(NDI_UNIQUE, 0, who,
  257.     "%s%s glows red, melts and evaporates!",
  258.             op->nrof?"":"The ",query_name(op));
  259. #ifdef SOUND_EFFECTS
  260.     play_sound_map(op->map, op->x, op->y, SOUND_OB_EVAPORATE);
  261. #endif
  262.     remove_ob(op);
  263.     free_object(op);
  264.     return;
  265. }
  266.  
  267. void polymorph_item(object *who, object *op) {
  268.   archetype *altern[MAX_ALT], *at;
  269.   int nr = 0, max_value, difficulty, tries=0,choice, charges=op->stats.food;
  270.   object *new_ob;
  271.  
  272.   max_value = op->value * 2;
  273.   if(max_value > 20000)
  274.     max_value = 20000 + (max_value - 20000) / 2;
  275.  
  276.   for(at = first_archetype ; at != NULL; at = at->next)
  277.     if(at->clone.type == op->type)
  278.     {
  279.       altern[nr] = at;
  280.       if(++nr == MAX_ALT)
  281.         break;
  282.     }
  283.   if(!nr)
  284.     return;
  285.  
  286.   difficulty = op->magic * 5;
  287.   if (difficulty<0) difficulty=0;
  288.   new_ob = get_object();
  289.   do {
  290.       choice = RANDOM()%nr;
  291.       copy_object(&(altern[choice]->clone),new_ob);
  292.       fix_generated_item(new_ob,op,difficulty,FABS(op->magic));
  293.       ++tries;
  294.   } while (new_ob->value > max_value && tries<10);
  295.   if (tries==10) {
  296.     polymorph_melt(who, op);
  297.     free_object(new_ob);
  298.     return;
  299.   }
  300.  
  301.   if(op->nrof && new_ob->nrof) {
  302.     new_ob->nrof = op->nrof;
  303.     /* decrease the number of items */
  304.     if (new_ob->nrof>2) new_ob->nrof -= RANDOM() % (op->nrof/2);
  305.   }
  306.   /* We don't want rings to keep sustenance/hungry status. There are propably
  307.      other cases too that should be checked. */
  308.   if(charges && op->type != RING && op->type != FOOD)
  309.       op->stats.food = charges;
  310.   new_ob->x = op->x;
  311.   new_ob->y = op->y;
  312.   remove_ob(op);
  313.   free_object(op);
  314.   insert_ob_in_map_simple(new_ob,who->map);
  315. }
  316.  
  317. void polymorph(object *op, object *who) {
  318.  
  319.   int tmp;
  320.  
  321.   if(op->type == PLAYER)
  322.     return; /* WILL add this later 8) */
  323.  
  324.   if(QUERY_FLAG(op, FLAG_MONSTER) || QUERY_FLAG(op,FLAG_GENERATOR)) {
  325.     polymorph_living(op);
  326.     return;
  327.   }
  328.   if(QUERY_FLAG(op, FLAG_ALIVE))
  329.     return;
  330.   if(FABS(op->speed) > 0.001 && !QUERY_FLAG(op, FLAG_ANIMATE))
  331.     return; /* Don't want to morph flying arrows, etc... */
  332.  
  333.   if(op->type == 0 || op->type==PLAYER || op->arch == NULL || 
  334.      QUERY_FLAG(op,FLAG_NO_PICK) 
  335.      || QUERY_FLAG(op, FLAG_NO_PASS) || op->type == TREASURE)
  336.     return;
  337.  
  338.   tmp = RANDOM() % 8;
  339.   if (tmp) polymorph_item(who, op);
  340.   else polymorph_melt(who, op);
  341. }
  342.  
  343. /*  allows the choice of what sort of food object to make.
  344.     If stringarg is NULL, it will create food dependent on level  --PeterM*/
  345. int cast_create_food(object *op,int dir, char *stringarg)
  346. {
  347.   int food_value;
  348.   archetype *at=NULL;
  349.   object *new_op;
  350.  
  351.   food_value=SP_PARAMETERS[SP_CREATE_FOOD].bdam
  352.               + 50 * SP_level_dam_adjust(op,SP_CREATE_FOOD);
  353.  
  354.   if(stringarg) {
  355.     at=find_archetype(stringarg);
  356.     if (at==NULL || ((at->clone.type != FOOD && at->clone.type != DRINK)
  357.         || (at->clone.stats.food > food_value)))
  358.         stringarg = NULL;
  359.   }
  360.   
  361.   if(!stringarg) {
  362.     if(food_value > 499) 
  363.         stringarg="waybread";
  364.     else if(food_value > 399)
  365.         stringarg="dragon_steak";
  366.     else if(food_value > 199)
  367.         stringarg="food";
  368.     else if(food_value > 124)
  369.         stringarg="cake";
  370.     else stringarg="booze";
  371.     at = find_archetype(stringarg);
  372.   }
  373.   food_value/=at->clone.stats.food;
  374.   new_op = get_object();
  375.   copy_object(&at->clone, new_op);
  376.   new_op->nrof = food_value;
  377.   if (new_op->nrof<1) new_op->nrof = 1;
  378.  
  379.   cast_create_obj(op, new_op, dir);
  380.   return 1;
  381. }
  382.   
  383.   
  384.  
  385. int cast_polymorph(object *op, int dir) {
  386.   object *tmp, *next;
  387.   int range;
  388.   archetype *poly;
  389.  
  390.   if(dir == 0)
  391.     return 0;
  392.   poly = find_archetype("polymorph");
  393.   for(range = 1;;range++) {
  394.     int x=op->x+freearr_x[dir]*range,y=op->y+freearr_y[dir]*range;
  395.     object *image;
  396.     if(wall(op->map,x,y) || blocks_magic(op->map,x,y))
  397.       break;
  398.     for(tmp = get_map_ob(op->map,x,y); tmp != NULL && tmp->above != NULL;
  399.         tmp = tmp->above);
  400.     while (tmp!=NULL) {
  401.       next = tmp->below;
  402.       polymorph(tmp, op);
  403.       tmp = next;
  404.     }
  405.     image = arch_to_object(poly);
  406.     image->x = x; image->y = y;
  407.     image->stats.food += range;
  408.     image->speed_left = 0.1;
  409.     insert_ob_in_map(image,op->map);
  410.   }
  411.   return 1;
  412. }
  413.  
  414. int cast_speedball(object *op, int dir, int type) {
  415.   object *spb;
  416.   if(blocked(op->map,op->x+freearr_x[dir],op->y+freearr_y[dir]))
  417.     return 0;
  418.   spb=clone_arch(SPEEDBALL);
  419.   spb->x=op->x+freearr_x[dir],spb->y=op->y+freearr_y[dir];
  420.   spb->speed_left= -0.1;
  421.   if(type==SP_LARGE_SPEEDBALL)
  422.     spb->stats.dam=30;
  423.   insert_ob_in_map(spb,op->map);
  424.   return 1;
  425. }
  426.  
  427. int probe(object *op, int dir) {
  428.   int r;
  429.   object *tmp;
  430.  
  431.   if(!dir) {
  432.     examine(op,op);
  433.     return 1;
  434.   }
  435.   for(r=1;;r++) {
  436.     int x=op->x+r*freearr_x[dir],y=op->y+r*freearr_y[dir];
  437.     if(out_of_map(op->map,x,y))
  438.       break;
  439.     if(blocks_magic(op->map,x,y)) {
  440.       new_draw_info(NDI_UNIQUE, 0,op,"Something blocks your magic.");
  441.       return 0;
  442.     }
  443.     for(tmp=get_map_ob(op->map,x,y);tmp!=NULL;tmp=tmp->above)
  444.       if(QUERY_FLAG(tmp, FLAG_ALIVE)&&(tmp->type==PLAYER||QUERY_FLAG(tmp, FLAG_MONSTER))) {
  445.         new_draw_info(NDI_UNIQUE, 0,op,"You detect something.");
  446.         if(tmp->head!=NULL)
  447.           tmp=tmp->head;
  448.         examine_monster(op,tmp);
  449.         return 1;
  450.       }
  451.   }
  452.   new_draw_info(NDI_UNIQUE, 0,op,"You detect nothing.");
  453.   return 1;
  454. }
  455.  
  456. int cast_invisible(object *op, int spell_type) {
  457.   object *tmp;
  458.  
  459.   if(op->invisible>1000) {
  460.     new_draw_info(NDI_UNIQUE, 0,op,"You are already as invisible as you can get.");
  461.     return 0;
  462.   }
  463.   switch(spell_type) {
  464.   case SP_INVIS:
  465.     CLEAR_FLAG(op, FLAG_UNDEAD);
  466.     op->invisible+=SP_PARAMETERS[spell_type].bdur;  /* set the base */
  467.     op->invisible+=SP_PARAMETERS[spell_type].ldam *
  468.                   SP_level_strength_adjust(op,spell_type);  /*  set the level bonus */
  469.     if(op->type==PLAYER)
  470.       op->contr->tmp_invis=1;
  471.     break;
  472.   case SP_INVIS_UNDEAD:
  473.     SET_FLAG(op, FLAG_UNDEAD);
  474.     op->invisible+=SP_PARAMETERS[spell_type].bdur;  /* set the base */
  475.     op->invisible+=SP_PARAMETERS[spell_type].ldam *
  476.                   SP_level_strength_adjust(op,spell_type);  /*  set the level bonus */
  477.  
  478.     if(op->type==PLAYER)
  479.       op->contr->tmp_invis=1;
  480.     break;
  481.   case SP_IMPROVED_INVIS:
  482.     op->invisible+=SP_PARAMETERS[spell_type].bdur;  /* set the base */
  483.     op->invisible+=SP_PARAMETERS[spell_type].ldam *
  484.                   SP_level_strength_adjust(op,spell_type);  /*  set the level bonus */
  485.     break;
  486.   }
  487.   new_draw_info(NDI_UNIQUE, 0,op,"You can't see your hands!");
  488.   update_object(op);
  489.   for (tmp = objects; tmp != NULL; tmp = tmp->next)
  490.     if (tmp->enemy == op)
  491.       tmp->enemy = NULL;
  492.   return 1;
  493. }
  494.  
  495.  
  496. int 
  497. cast_earth2dust( object *op ) {
  498.   object *tmp, *next;
  499.   int strength,i,j;
  500.  
  501.   if(op->type!=PLAYER)
  502.     return 0;
  503.   strength=SP_PARAMETERS[SP_EARTH_DUST].bdur + SP_level_strength_adjust(op,SP_EARTH_DUST);
  504.   strength=(strength>15)?15:strength;
  505.   for(i= -strength;i<strength;i++)
  506.     for(j= -strength;j<strength;j++) {
  507.       if(out_of_map(op->map,op->x+i,op->y+j))
  508.         continue;
  509.       for(tmp=get_map_ob(op->map,op->x+i,op->y+j);tmp!=NULL;tmp=next) {
  510.         next=tmp->above;
  511.         if(tmp&&QUERY_FLAG(tmp, FLAG_TEAR_DOWN))
  512.           hit_player(tmp,9999,op,AT_PHYSICAL);
  513.       }
  514.     }
  515.   return 1;
  516. }
  517.  
  518. /* puts a 'WORD_OF_RECALL_' object in player */
  519. int cast_wor(object *op) {
  520.   object *dummy;
  521.   if(op->type!=PLAYER)
  522.     return 0;
  523.   if(blocks_magic(op->map,op->x,op->y)) {
  524.     new_draw_info(NDI_UNIQUE, 0,op,"Something blocks your spell.");
  525.     return 0;
  526.   }
  527.   dummy=get_object();
  528.   if(dummy == NULL){
  529.     new_draw_info(NDI_UNIQUE, 0,op,"Oops, program error!");
  530.     LOG(llevError,"get_object failed!\n");
  531.     return 0;
  532.   }
  533.   if(op->owner) op=op->owner; /* better insert the spell in the player */
  534.   dummy->invisible=1;
  535.   dummy->speed = 0.01;
  536.   update_ob_speed(dummy);
  537.   dummy->speed_left= -1;
  538.   dummy->type=WORD_OF_RECALL;
  539.   EXIT_PATH(dummy)=add_string(first_map_path);
  540.   (void) insert_ob_in_ob(dummy,op);
  541.   new_draw_info(NDI_UNIQUE, 0,op,"You feel a force starting to build up inside you.");
  542.   return 1;
  543. }
  544.  
  545. int cast_wow(object *op, int dir, int ability, SpellTypeFrom item) {
  546.   int sp;
  547.   if(!(RANDOM()%4))
  548.     return cast_cone(op,0,10,SP_WOW,spellarch[SP_WOW],0);
  549.   do
  550.     sp=RANDOM()%NROFREALSPELLS;
  551.   while (!spells[sp].books);
  552.   return cast_spell(op,op,dir,sp,ability,item,NULL);
  553. }
  554.  
  555. int perceive_self(object *op) {
  556.   char *cp=describe_item(op), buf[MAX_BUF];
  557.   archetype *at=find_archetype("depletion");
  558.   object *tmp;
  559.   int i;
  560.  
  561.   tmp=present_arch_in_ob(at,op);
  562.  
  563.   if(*cp=='\0' && tmp==NULL)
  564.     new_draw_info(NDI_UNIQUE, 0,op,"You feel very mundane");
  565.   else {
  566.     new_draw_info(NDI_UNIQUE, 0,op,"You have:");
  567.     new_draw_info(NDI_UNIQUE, 0,op,cp);
  568.     if (tmp!=NULL) {
  569.       for (i=0; i<7; i++) {
  570.     if (get_attr_value(&tmp->stats, i)<0) {
  571.       sprintf(buf,"Your %s is depleted by %d", statname[i],
  572.         -(get_attr_value(&tmp->stats,i)));
  573.       new_draw_info(NDI_UNIQUE, 0,op, buf);
  574.     }
  575.       }
  576.     }
  577.   }
  578.   return 1;
  579. }
  580.  
  581. int cast_destruction(object *op, int dam, int attacktype) {
  582.   int i,j;
  583.   int r;    /*  peterm:  added to make area of effect level dep.  */
  584.   object *tmp;
  585.   if(op->type!=PLAYER)
  586.     return 0;
  587.   r=5 + SP_level_strength_adjust(op,SP_DESTRUCTION);
  588.   dam+=SP_level_dam_adjust(op,SP_DESTRUCTION);
  589.   for(i= -r;i<r;i++)
  590.     for(j= -r;j<r;j++) {
  591.       if(out_of_map(op->map,op->x+i,op->y+j))
  592.         continue;
  593.       tmp=get_map_ob(op->map,op->x+i,op->y+j);
  594.       while(tmp!=NULL&&(!QUERY_FLAG(tmp, FLAG_ALIVE)||tmp->type==PLAYER))
  595.         tmp=tmp->above;
  596.       if(tmp==NULL)
  597.         continue;
  598.       hit_player(tmp,dam,op,attacktype);
  599.     }
  600.   return 1;
  601. }
  602.  
  603. int magic_wall(object *op,int dir,int spell_type) {
  604.   object *tmp;
  605.   if(!dir) {
  606.     new_draw_info(NDI_UNIQUE, 0,op,"In what direction?");
  607.     return 0;
  608.   }
  609.   if(blocked(op->map,op->x+freearr_x[dir],op->y+freearr_y[dir])) {
  610.     new_draw_info(NDI_UNIQUE, 0,op,"Something is in the way.");
  611.     return 0;
  612.   }
  613.   switch(spell_type) {
  614.   case SP_EARTH_WALL:
  615.     tmp=get_archetype("earthwall");
  616.     tmp->immune=0,tmp->protected=0;
  617.     tmp->stats.hp = SP_PARAMETERS[spell_type].bdur +
  618.                   10* SP_level_strength_adjust(op,spell_type);
  619.     /* More solid, since they can be torn down */
  620.     tmp->stats.maxhp = tmp->stats.hp;
  621. #if 0
  622.     /* Don't make them friendly - ends up making them too hard hard for other
  623.      * players to kill
  624.      */
  625.     /*
  626.      *  Now, make agressive monsters tear down the walls:
  627.      */
  628.     SET_FLAG(tmp, FLAG_FRIENDLY);
  629.     add_friendly_object(tmp);
  630. #endif
  631.     break;
  632.   case SP_FIRE_WALL:
  633.     tmp=get_archetype("firebreath");
  634.     tmp->attacktype |= AT_MAGIC;
  635.     tmp->stats.hp=SP_PARAMETERS[spell_type].bdur
  636.               + 5*SP_level_strength_adjust(op,spell_type);
  637.     tmp->stats.dam=SP_PARAMETERS[spell_type].bdam
  638.                   +SP_level_dam_adjust(op,spell_type);
  639.     tmp->stats.food=1;                        /* so it doesn't propagate */
  640. #if 0
  641.     SET_SLOW_MOVE(tmp);
  642.     SET_SLOW_PENALTY(tmp,2);
  643. #endif
  644.     SET_FLAG(tmp, FLAG_WALK_ON);
  645.     SET_FLAG(tmp, FLAG_FLY_ON);
  646.     set_owner(tmp,op);
  647.     break;
  648.   case SP_FROST_WALL:
  649.     tmp=get_archetype("icestorm");
  650.     tmp->attacktype |= AT_MAGIC;
  651.     tmp->stats.hp=SP_PARAMETERS[spell_type].bdur
  652.               + 5*SP_level_strength_adjust(op,spell_type);
  653.     tmp->stats.dam=SP_PARAMETERS[spell_type].bdam
  654.                   +SP_level_dam_adjust(op,spell_type);
  655.  
  656.     tmp->stats.food=1;                        /* so it doesn't propagate */
  657. #if 0
  658.     SET_SLOW_MOVE(tmp);
  659.     SET_SLOW_PENALTY(tmp,3);
  660. #endif
  661.     SET_FLAG(tmp, FLAG_WALK_ON);
  662.     SET_FLAG(tmp, FLAG_FLY_ON);
  663.     set_owner(tmp,op);
  664.     break;
  665.   case SP_WALL_OF_THORNS:
  666.     tmp=get_archetype("thorns");
  667.     tmp->stats.hp=SP_PARAMETERS[spell_type].bdur
  668.               + 5*SP_level_strength_adjust(op,spell_type);
  669.     tmp->stats.dam=SP_PARAMETERS[spell_type].bdam
  670.                   +SP_level_dam_adjust(op,spell_type);
  671.     SET_FLAG(tmp, FLAG_WALK_ON);
  672.     SET_FLAG(tmp, FLAG_FLY_ON);
  673.     SET_FLAG(tmp, FLAG_BLOCKSVIEW);
  674.     set_owner(tmp,op);
  675.     break;
  676.   case SP_CHAOS_POOL:
  677.     tmp=get_archetype("color_spray");
  678.     tmp->attacktype|=AT_MAGIC;
  679.     tmp->stats.hp=SP_PARAMETERS[spell_type].bdur
  680.               + 5*SP_level_strength_adjust(op,spell_type);
  681.     tmp->stats.dam=SP_PARAMETERS[spell_type].bdam
  682.                   +SP_level_dam_adjust(op,spell_type);
  683.  
  684.     tmp->stats.food=1;  /* so the color spray object won't propagate */
  685.     SET_FLAG(tmp, FLAG_WALK_ON);
  686.     SET_FLAG(tmp, FLAG_FLY_ON);
  687.     set_owner(tmp,op);
  688.     break;
  689.   case SP_DARKNESS:
  690.     tmp=get_archetype("darkness");
  691.     tmp->speed = 0.000001 * (SP_PARAMETERS[SP_DARKNESS].bdur
  692.               - (10*SP_level_strength_adjust(op,SP_DARKNESS)));
  693.     break; 
  694.   case SP_COUNTERWALL:
  695.     tmp=get_archetype("counterspell");
  696.     tmp->attacktype|=AT_MAGIC;
  697.     tmp->stats.hp=SP_PARAMETERS[spell_type].bdur
  698.               + 5*SP_level_strength_adjust(op,spell_type);
  699.     tmp->stats.dam=SP_PARAMETERS[spell_type].bdam
  700.                   +SP_level_dam_adjust(op,spell_type);
  701.     tmp->stats.food=1;
  702.  
  703. /*
  704.     tmp->level=op->level;
  705. */
  706.     tmp->level=SK_level(op);
  707.     SET_FLAG(tmp, FLAG_WALK_ON);
  708.     SET_FLAG(tmp, FLAG_FLY_ON);
  709.     set_owner(tmp,op);
  710.     break;
  711.   default:
  712.     LOG(llevError,"Unimplemented magic_wall spell: %d\n",spell_type);
  713.     return 0;
  714.   }
  715.   tmp->x=op->x+freearr_x[dir],tmp->y=op->y+freearr_y[dir];
  716.   insert_ob_in_map(tmp,op->map);
  717.   if(QUERY_FLAG(tmp, FLAG_BLOCKSVIEW))
  718.     update_all_los(op->map);
  719.   if(op->type==PLAYER)
  720.     draw(op);
  721.   else
  722.     SET_FLAG(op, FLAG_SCARED); /* We don't want them to walk through the wall! */
  723.   return 1;
  724. }
  725.  
  726. /* cast_light() - I wanted this to be able to blind opponents who stand
  727.  * adjacent to the caster, so I couldnt use magic_wall(). -b.t. 
  728.  */
  729.  
  730. int cast_light(object *op,int dir) {
  731.   object *target=NULL,*tmp=NULL;
  732.   int x,y,dam=SP_PARAMETERS[SP_LIGHT].bdam    
  733.                   +SP_level_dam_adjust(op,SP_LIGHT);;
  734.  
  735.   if(!dir) {
  736.     new_draw_info(NDI_UNIQUE, 0,op,"In what direction?");
  737.     return 0;
  738.   }
  739.  
  740.   x=op->x+freearr_x[dir],y=op->y+freearr_y[dir];
  741.  
  742.   for(target=get_map_ob(op->map,x,y);target;target=target->above)
  743.      if(QUERY_FLAG(target,FLAG_MONSTER)) {
  744.         /* coky doky. got a target monster. Lets make a blinding attack */ 
  745.          if(target->head) target = target->head; 
  746.          (void) hit_player(target,dam,op,(AT_BLIND|AT_MAGIC));
  747.          return 1; /* one success only! */
  748.       }
  749.  
  750.   /* no live target, perhaps a wall is in the way? */
  751.   if(blocked(op->map,x,y)) {
  752.       new_draw_info(NDI_UNIQUE, 0,op,"Something is in the way.");
  753.       return 0;
  754.   }
  755.   /* ok, looks groovy to just insert a new light on the map */
  756.   tmp=get_archetype("light");
  757.   if(!tmp) { 
  758.     LOG(llevError,"Error: spell arch for cast_light() missing.\n");
  759.     return 0;
  760.   }
  761.   tmp->speed = 0.000001 * (SP_PARAMETERS[SP_LIGHT].bdur
  762.               - (10*SP_level_strength_adjust(op,SP_LIGHT)));
  763.   tmp->glow_radius=dam;
  764.   tmp->x=x,tmp->y=y;
  765.   if(tmp->speed<=0) tmp->speed = 0.000001; /* safety */
  766.   insert_ob_in_map(tmp,op->map);
  767.  
  768.   if(op->type==PLAYER) draw(op);
  769.   return 1;
  770. }
  771.  
  772. int dimension_door(object *op,int dir) {
  773.   int dist;
  774.   if(!dir) {
  775.     new_draw_info(NDI_UNIQUE, 0,op,"In what direction?");
  776.     return 0;
  777.   }
  778.   if(op->type!=PLAYER)
  779.     return 0;
  780.   if(op->contr->count) {
  781.     for(dist=0;dist<op->contr->count&&
  782.                !blocks_magic(op->map,op->x+freearr_x[dir]*(dist+1),
  783.                              op->y+freearr_y[dir]*(dist+1));
  784.         dist++);
  785.     if(dist<op->contr->count) {
  786.       new_draw_info(NDI_UNIQUE, 0,op,"Something blocks your magic.\n");
  787.       op->contr->count=0;
  788.       return 0;
  789.     }
  790.     op->contr->count=0;
  791.     if(blocked(op->map,op->x+freearr_x[dir]*dist,
  792.                        op->y+freearr_y[dir]*dist))
  793.     { /* Now the fun starts... 8) */
  794.       int x=RANDOM()%op->map->mapx,y=RANDOM()%op->map->mapy;
  795.       if(blocked(op->map,x,y)) { /* Lucky after all... */
  796.         new_draw_info(NDI_UNIQUE, 0,op,"You cast your spell, but nothing happens.\n");
  797.         return 1; /* Maybe the penalty should be more severe... */
  798.       }
  799.       remove_ob(op);
  800.       op->x=x,op->y=y;
  801.       insert_ob_in_map(op,op->map);
  802.       draw(op);
  803.       return 1;
  804.     }
  805.   } /* if op->contr->count*/ else {
  806.     for(dist=0;!blocks_view (op->map,op->x+freearr_x[dir]*(dist+1),
  807.                                      op->y+freearr_y[dir]*(dist+1))&&
  808.                !blocks_magic(op->map,op->x+freearr_x[dir]*(dist+1),
  809.                                      op->y+freearr_y[dir]*(dist+1));
  810.         dist++);
  811.     for(;dist>0&&blocked(op->map,op->x+freearr_x[dir]*dist,
  812.                                  op->y+freearr_y[dir]*dist);dist--);
  813.     if(!dist) {
  814.       new_draw_info(NDI_UNIQUE, 0,op,"Your spell failed!\n");
  815.       return 0;
  816.     }
  817.   }
  818.   remove_ob(op);
  819.   op->x+=freearr_x[dir]*dist,op->y+=freearr_y[dir]*dist;
  820.   insert_ob_in_map(op,op->map);
  821.   draw(op);
  822.   op->speed_left= -FABS(op->speed)*5; /* Freeze them for a short while */
  823.   return 1;
  824. }
  825.  
  826.  
  827.  
  828. int
  829. cast_heal(object *op,int dir,int spell_type) {
  830.   object *tmp;
  831.   archetype *at;
  832.   object *poison;
  833.   int heal=0;
  834.  
  835.   tmp = find_target_for_friendly_spell(op,dir);
  836.  
  837.   if(tmp==NULL) return 0;
  838.   switch(spell_type) {
  839.   case SP_MINOR_HEAL:
  840.     heal=(RANDOM()%7)+1;
  841.     new_draw_info(NDI_UNIQUE, 0,tmp, "Your wounds start to close.");
  842.     break;
  843.   case SP_MED_HEAL:
  844.     heal=(RANDOM()%6)+(RANDOM()%6)+(RANDOM()%6)+7;
  845.     new_draw_info(NDI_UNIQUE, 0,tmp, "Your wounds start to fade.");
  846.     break;
  847.   case SP_MAJOR_HEAL:
  848.     new_draw_info(NDI_UNIQUE, 0,tmp, "Your skin looks as good as new!");
  849.     heal=(RANDOM()%8)+(RANDOM()%8)+(RANDOM()%8)+(RANDOM()%8)+12;
  850.     break;
  851.   case SP_HEAL:
  852.     heal=tmp->stats.maxhp;  /* or should be this tmp->stats.maxhp? */
  853.     new_draw_info(NDI_UNIQUE, 0,tmp, "You feel just fine!");
  854.     break;
  855.   case SP_CURE_POISON: 
  856.     at = find_archetype("poisoning");
  857.     poison=present_arch_in_ob(at,tmp);
  858.  
  859.     if (poison) {
  860.       new_draw_info(NDI_UNIQUE, 0,tmp, "Your body feels cleansed");
  861.       poison->stats.food = 1;
  862.     }
  863.     break;                            
  864.   case SP_CURE_CONFUSION:
  865.     at=find_archetype("confusion");
  866.     poison=present_arch_in_ob(at,tmp);
  867.     if (poison) {
  868.       new_draw_info(NDI_UNIQUE, 0,tmp, "Your mind feels clearer");
  869.       poison->stats.food = 1;
  870.     }
  871.     break;
  872.   case SP_CURE_BLINDNESS:
  873.     at=find_archetype("blindness");
  874.     poison=present_arch_in_ob(at,tmp);
  875.     if (poison) {
  876.       new_draw_info(NDI_UNIQUE, 0,tmp,"Your vision begins to return.");
  877.       poison->stats.food = 1;
  878.     }
  879.     break;
  880.   case SP_RESTORATION:  /* does cure poison, cure madness, heal,and removes depletion, food=999. */
  881.     cast_heal(op,dir,SP_CURE_POISON);
  882.     cast_heal(op,dir,SP_CURE_CONFUSION);
  883.     tmp->stats.food=999;
  884. #if 0
  885.     /* Leave removing depletion to the restore potion. */
  886.     at=find_archetype("depletion");
  887.     poison=present_arch_in_ob(at,tmp);
  888.     if (poison) {
  889.       new_draw_info(NDI_UNIQUE, 0,tmp, "Your abilities seem to have recovered.");
  890.       remove_ob(poison);
  891.       free_object(poison);
  892.       poison = present_arch_in_ob(at, tmp);
  893.     }
  894. #endif
  895.     cast_heal(op,dir,SP_HEAL);  /*  put this one last because
  896.                     it'll redraw the stats
  897.                     as a side effect. */
  898.     return 1;
  899.   }
  900.   if (tmp->stats.hp==tmp->stats.maxhp)
  901.     return 0;
  902.   tmp->stats.hp+=heal;
  903.   if(tmp->stats.hp>tmp->stats.maxhp)
  904.     tmp->stats.hp=tmp->stats.maxhp;
  905.   if(tmp->type==PLAYER)
  906.     draw_stats(tmp);
  907.   if(op!=tmp && op->type==PLAYER)
  908.     draw_stats(op);
  909.   op->speed_left= -FABS(op->speed)*3; /* Freeze them for a short while */
  910.   return 1;
  911. }
  912.  
  913. int cast_regenerate_spellpoints(object *op) {
  914.   object *tmp;
  915.  
  916.   tmp = find_target_for_friendly_spell(op,0);
  917.  
  918.   if(tmp==NULL) return 0;
  919.  
  920.   tmp->stats.sp = tmp->stats.maxsp;
  921.   if (tmp->type == PLAYER)
  922.     draw_stats(tmp);
  923.   new_draw_info(NDI_UNIQUE, 0,tmp, "Magical energies surge through your body!");
  924.   return 1;
  925. }
  926.  
  927. int
  928. cast_change_attr(object *op,int dir,int spell_type) {
  929.   object *tmp = op;
  930.   object *force;
  931.   int i;
  932.  
  933.   /* if dir = 99 op defaults to tmp, eat_special_food() requires this. */
  934.   if(dir!=99)
  935.      tmp=find_target_for_friendly_spell(op,dir);
  936.  
  937.   if(tmp==NULL) return 0;
  938.  
  939. /*  if((force=present_in_ob(FORCE,tmp))!=NULL)
  940.     remove_force(force);
  941.     We should be able to have more than one thing in force! */
  942.   force=get_archetype("force");
  943.   switch(spell_type) {
  944.   case SP_STRENGTH:
  945.     if(tmp->type!=PLAYER)
  946.       break;
  947.     if(!(RANDOM()%(MAX(1,(10 - MAX_STAT + tmp->stats.Str))))) {
  948.     for(i=20,force->stats.Str=1;i>tmp->stats.Str;i-=2)
  949.       force->stats.Str++; }
  950.         else { new_draw_info(NDI_UNIQUE, 0,op,"You grow no stronger."); force->stats.Str=0; }
  951.     break;
  952.   case SP_DEXTERITY:
  953.     if(tmp->type!=PLAYER)
  954.       break;
  955.     if(!(RANDOM()%(MAX(1,(10 - MAX_STAT + tmp->stats.Dex))))) {
  956.     for(i=20,force->stats.Dex=1;i>tmp->stats.Dex;i-=2)
  957.       force->stats.Dex++; }
  958.         else { new_draw_info(NDI_UNIQUE, 0,op,"You grow no more agile."); force->stats.Dex=0; }
  959.  
  960.     break;
  961.   case SP_CONSTITUTION:
  962.     if(tmp->type!=PLAYER)
  963.       break;
  964.     if(!(RANDOM()%(MAX(1,(10 - MAX_STAT + tmp->stats.Con))))) {
  965.     for(i=20,force->stats.Con=1;i>tmp->stats.Con;i-=2)
  966.       force->stats.Con++;}
  967.         else { new_draw_info(NDI_UNIQUE, 0,op,"You don't feel any healthier."); force->stats.Con=0; }
  968.  
  969.     break;
  970.   case SP_CHARISMA:
  971.     if(tmp->type!=PLAYER)
  972.       break;
  973.     if(!(RANDOM()%(MAX(1,(10 - MAX_STAT + tmp->stats.Cha))))) {
  974.     for(i=20,force->stats.Cha=1;i>tmp->stats.Cha;i-=2)
  975.       force->stats.Cha++;}
  976.         else { new_draw_info(NDI_UNIQUE, 0,op,"You are no easier to look at."); force->stats.Cha=0; }
  977.  
  978.     break;
  979.   case SP_ARMOUR: {
  980.    /* peterm, modified so that it uses my functions */
  981.     force->stats.ac=2+SP_level_dam_adjust(op,spell_type);
  982.     if((tmp->stats.ac-force->stats.ac)<-20) 
  983.     force->stats.ac=tmp->stats.ac+20;
  984.  
  985. /*    if(force->stats.ac>5)
  986.       force->stats.ac=5;  */
  987.     force->armour = 5+4*SP_level_dam_adjust(op,spell_type);
  988.     if (force->armour > 25)
  989.       force->armour = 25;
  990.     if(tmp->armour>70&& force->armour>(100-tmp->armour)/3)
  991.     force->armour=3;  /* diminishing returns at high armor. */
  992.     new_draw_info(NDI_UNIQUE, 0,tmp,"A force shimmers around you.");
  993.     break; }
  994.   case SP_CONFUSION:
  995.     force->attacktype |= (AT_CONFUSION|AT_PHYSICAL);
  996.     force->protected |= AT_CONFUSION;
  997.     break;
  998.   case SP_HEROISM:
  999.     if (tmp->type != PLAYER)
  1000.       break;
  1001. /*    if (tmp->contr->orig_stats.Str > 19)
  1002.       force->stats.Str = 1;
  1003.     else
  1004.       force->stats.Str = 2;
  1005.     if (tmp->contr->orig_stats.Con > 19)
  1006.       force->stats.Con = 1;
  1007.     else if (tmp->contr->orig_stats.Con > 15)
  1008.       force->stats.Con = 2;
  1009.     else
  1010.       force->stats.Con = 3;  */
  1011.   /*  peterm: heroism is much more elegantly implemented by
  1012.     having it cast stat spells for con, str, dex.  Repeated
  1013.     castings will make you more heroic, but only up to a point */
  1014.     cast_change_attr(op,dir,SP_STRENGTH);
  1015.     cast_change_attr(op,dir,SP_DEXTERITY);
  1016.     cast_change_attr(op,dir,SP_CONSTITUTION);
  1017.     break;
  1018.   case SP_HOLY_POSSESSION: {
  1019. #ifdef MULTIPLE_GODS
  1020.     int godnr = lookup_god_by_name(determine_god(op));
  1021.     if(godnr>=0) {
  1022.       force->attacktype|=Gods[godnr].attacktype;
  1023.       if(strcmp(Gods[godnr].enemy_race,"none"))
  1024.          force->slaying = add_string(Gods[godnr].enemy_race);
  1025.       if(Gods[godnr].immune) force->immune|=Gods[godnr].immune;
  1026.       if(Gods[godnr].protected) force->protected|=Gods[godnr].protected;
  1027.       if(Gods[godnr].path_attuned) force->path_attuned|=Gods[godnr].path_attuned;
  1028.       new_draw_info_format(NDI_UNIQUE, 0,tmp,
  1029.        "You become possessed by the spirit of %s!",Gods[godnr].name);
  1030.     } else 
  1031.         new_draw_info(NDI_UNIQUE, 0,op,"Your blessing seems empty.");
  1032. #endif
  1033.     if(tmp!=op) new_draw_info_format(NDI_UNIQUE, 0,tmp,
  1034.     "You bless %s mightily!",tmp->name);
  1035.     force->stats.wc += SP_level_dam_adjust(op, SP_HOLY_POSSESSION); 
  1036.     force->stats.ac += SP_level_dam_adjust(op, SP_HOLY_POSSESSION); 
  1037.     break; } 
  1038.   case SP_REGENERATION:
  1039.     force->stats.hp = 1 + SP_level_dam_adjust(op, SP_REGENERATION);
  1040.     break;
  1041.   case SP_CURSE: {  
  1042. #ifdef MULTIPLE_GODS
  1043.     int godnr = lookup_god_by_name(determine_god(op));
  1044.     if(godnr>=0) {
  1045.       if(Gods[godnr].path_repelled)
  1046.       force->path_repelled|=Gods[godnr].path_repelled;
  1047.       if(Gods[godnr].path_denied)
  1048.           force->path_denied|=Gods[godnr].path_denied;
  1049.       new_draw_info_format(NDI_UNIQUE, 0,tmp,
  1050.     "You are a victim of %s's curse!",Gods[godnr].name);
  1051.     } else 
  1052.         new_draw_info(NDI_UNIQUE, 0,op,"Your curse seems empty.");
  1053. #endif
  1054.     if(tmp!=op) new_draw_info_format(NDI_UNIQUE, 0,tmp,"You curse %s!",tmp->name);
  1055.     force->stats.ac -= SP_level_dam_adjust(op, SP_CURSE); 
  1056.     force->stats.wc -= SP_level_dam_adjust(op, SP_CURSE);
  1057.     break; } 
  1058.   case SP_BLESS: { 
  1059. #ifdef MULTIPLE_GODS
  1060.     int godnr = lookup_god_by_name(determine_god(op));
  1061.     if(godnr>=0) {
  1062.        if(Gods[godnr].protected) force->protected|=Gods[godnr].protected;
  1063.        if(Gods[godnr].path_attuned) force->path_attuned|=Gods[godnr].path_attuned;
  1064.           new_draw_info_format(NDI_UNIQUE, 0,tmp,
  1065.         "You receive the blessing of %s.",Gods[godnr].name);
  1066.     } else 
  1067.         new_draw_info(NDI_UNIQUE, 0,op,"Your blessing seems empty.");
  1068. #endif
  1069.     if(tmp!=op) new_draw_info_format(NDI_UNIQUE, 0,tmp,"You bless %s.",tmp->name);
  1070.     force->stats.wc += SP_level_dam_adjust(op, SP_BLESS);
  1071.     force->stats.ac += SP_level_dam_adjust(op, SP_BLESS);
  1072.     break; } 
  1073.   case SP_DARK_VISION:
  1074.     SET_FLAG(force,FLAG_SEE_IN_DARK);
  1075.     break;
  1076.   case SP_PROT_COLD:
  1077.     force->protected|=AT_COLD;
  1078.     break;
  1079.   case SP_PROT_FIRE:
  1080.     force->protected|=AT_FIRE;
  1081.     break;
  1082.   case SP_PROT_ELEC:
  1083.     force->protected|=AT_ELECTRICITY;
  1084.     break;
  1085.   case SP_PROT_POISON:
  1086.     force->protected|=AT_POISON;
  1087.     break;
  1088.   case SP_PROT_SLOW:
  1089.     force->protected|=AT_SLOW;
  1090.     break;
  1091.   case SP_PROT_PARALYZE:
  1092.     force->protected|=AT_PARALYZE;
  1093.     break;
  1094.   case SP_PROT_DRAIN:
  1095.     force->protected|=AT_DRAIN;
  1096.     break;
  1097.   case SP_PROT_ATTACK:
  1098.     force->protected|=AT_PHYSICAL;
  1099.     break;
  1100.   case SP_PROT_MAGIC:
  1101.     force->protected|=AT_MAGIC;
  1102.     break;
  1103.   case SP_PROT_CONFUSE:
  1104.     force->protected|=AT_CONFUSION;
  1105.     break;
  1106.   case SP_PROT_CANCEL:
  1107.     force->protected|=AT_CANCELLATION;
  1108.     break;
  1109.   case SP_PROT_DEPLETE:
  1110.     force->protected|=AT_DEPLETE;
  1111.     break;
  1112.   case SP_LEVITATE:
  1113.     SET_FLAG(force, FLAG_FLYING);
  1114.     break;
  1115.     /*mlee*/
  1116.   case SP_IMMUNE_COLD:
  1117.     force->immune|=AT_COLD;
  1118.     break;
  1119.   case SP_IMMUNE_FIRE:
  1120.     force->immune|=AT_FIRE;
  1121.     break;
  1122.   case SP_IMMUNE_ELEC:
  1123.     force->immune|=AT_ELECTRICITY;
  1124.     break;
  1125.   case SP_IMMUNE_POISON:
  1126.     force->immune|=AT_POISON;
  1127.     break;
  1128.   case SP_IMMUNE_SLOW:
  1129.     force->immune|=AT_SLOW;
  1130.     break;
  1131.   case SP_IMMUNE_PARALYZE:
  1132.     force->immune|=AT_PARALYZE;
  1133.     break;
  1134.   case SP_IMMUNE_DRAIN:
  1135.     force->immune|=AT_DRAIN;
  1136.     break;
  1137.   case SP_IMMUNE_ATTACK:
  1138.     force->immune|=AT_PHYSICAL;
  1139.     break;
  1140.   case SP_IMMUNE_MAGIC:
  1141.     force->immune|=AT_MAGIC;
  1142.     break;
  1143.   case SP_INVULNERABILITY:
  1144.     force->immune|=262143;
  1145.     break;
  1146.   case SP_PROTECTION:
  1147.     force->protected|=262143;
  1148.     break;
  1149.   case SP_HASTE:
  1150.     force->stats.exp=(3+SP_level_dam_adjust(op, SP_HASTE));
  1151.     if(op->speed > 0.2 * SP_level_strength_adjust(op,SP_HASTE)) 
  1152.     force->stats.exp=0;
  1153.     break;
  1154.   case SP_XRAY:
  1155.     SET_FLAG(force,FLAG_XRAYS);
  1156.     break;
  1157.  
  1158.   }
  1159.   force->speed_left= -1-SP_level_strength_adjust(op, spell_type)*0.1;
  1160.   SET_FLAG(force, FLAG_APPLIED);
  1161.   force = insert_ob_in_ob(force,tmp);
  1162.   change_abil(tmp,force); /* Mostly to display any messages */
  1163.   fix_player(tmp);        /* This takes care of some stuff that change_abil() */
  1164.               /* unfortunately is incapable off. */
  1165.   if(tmp->type==PLAYER)
  1166.     draw_stats(tmp);
  1167.   return 1;
  1168. }
  1169.  
  1170.  
  1171. #define MAX_PET_MONSTERS 5
  1172. char mage_pet_monsters [MAX_PET_MONSTERS][16] =
  1173.                 {"bat","spider","stalker","beholder","dark_elf"};
  1174. int mage_num_called [MAX_PET_MONSTERS] = {2,1,1,2,3};
  1175. char priest_pet_monsters [MAX_PET_MONSTERS][16] =
  1176.                 {"bee","killer_bee","devil","angel","panther"};
  1177. int priest_num_called [MAX_PET_MONSTERS] = {3,2,2,2,5};
  1178. char altern_pet_monsters [MAX_PET_MONSTERS][16] =
  1179.                 {"bird","pixie","skeleton","skull","vampire"};
  1180. int altern_num_called [MAX_PET_MONSTERS] = {1,1,2,1,1};
  1181.  
  1182. /* this pet monster stuff is total crap!
  1183. ** We should replace it with:
  1184. struct summoned_mon int foo {
  1185.         char * mon_arch;
  1186.         int  num_summoned;
  1187.         }
  1188. struct summoned_mon pets_summoned = {
  1189.        { "bird", 5 },
  1190.        { "vampire", 6},
  1191.        { NULL, 0 }     -* terminator *-
  1192. }
  1193. **
  1194. */
  1195.  
  1196.  
  1197. int summon_pet(object *op, int dir, SpellTypeFrom item) {
  1198.   int level, number, i;
  1199.   char *monster;
  1200.   archetype *at;
  1201.  
  1202. /*
  1203.   level = ((op->head?op->head->level:op->level) / 4); 
  1204. */
  1205.   level = ((op->head?op->head->level:SK_level(op)) / 4);
  1206.   if (level >= MAX_PET_MONSTERS)
  1207.     level = MAX_PET_MONSTERS - 1;
  1208.   switch(RANDOM()%3) {
  1209.   case 0:
  1210.     number = priest_num_called[level];
  1211.     monster = priest_pet_monsters[level];
  1212.     break;
  1213.   case 1:
  1214.     number = mage_num_called[level];
  1215.     monster = mage_pet_monsters[level];
  1216.     break;
  1217.   default:
  1218.     number = altern_num_called[level];
  1219.     monster = altern_pet_monsters[level];
  1220.     break;
  1221.   }
  1222.   at = find_archetype(monster);
  1223.   if(at == NULL) {
  1224.     LOG(llevError,"Unknown archetype in summon pet: %s\n",monster);
  1225.     return 0;
  1226.   }
  1227.   if (!dir)
  1228.     dir = find_free_spot(at, op->map, op->x, op->y, 1, SIZEOFFREE);
  1229.   if(arch_blocked(at,op->map, op->x + freearr_x[dir], op->y+freearr_y[dir]))
  1230.   {
  1231.     new_draw_info(NDI_UNIQUE, 0,op, "There is something in the way.");
  1232.     if(op->type == PLAYER)
  1233.       op->contr->count_left = 0;
  1234.     return 0;
  1235.   }
  1236.   if (item != spellNormal)
  1237.     /* op->stats.sp -= 5 + 10*level + op->level; */ 
  1238.     op->stats.sp -= 5 + 10*level + SK_level(op);
  1239.   for (i = 1; i < number + 1; i++) {
  1240.     archetype *atmp;
  1241.     object *prev = NULL, *head = NULL; /* We want to summon dragons *grin* */
  1242.  
  1243.     for(atmp = at; atmp!=NULL; atmp = atmp->more) {
  1244.       object *tmp;
  1245.       tmp = arch_to_object(atmp);
  1246.       if (atmp == at) {
  1247.         set_owner(tmp, op);
  1248.         SET_FLAG(tmp, FLAG_MONSTER);
  1249.         if (op->type == PLAYER) {
  1250.           tmp->stats.exp = 0;
  1251.           add_friendly_object(tmp);
  1252.           SET_FLAG(tmp, FLAG_FRIENDLY);
  1253.           tmp->move_type = PETMOVE;
  1254.         } else
  1255.           if(QUERY_FLAG(op, FLAG_FRIENDLY)) {
  1256.             add_friendly_object(tmp);
  1257.             SET_FLAG(tmp, FLAG_FRIENDLY);
  1258.             tmp->move_type = PETMOVE;
  1259.           } else
  1260.         tmp->speed_left = -1;
  1261.         tmp->enemy = op->enemy;
  1262.         tmp->type = 0;
  1263.       }
  1264.       if(head == NULL)
  1265.         head = tmp;
  1266.       tmp->x = op->x + freearr_x[dir] + tmp->arch->clone.x;
  1267.       tmp->y = op->y + freearr_y[dir] + tmp->arch->clone.y;
  1268.       tmp->map = op->map;
  1269.       if(head != tmp)
  1270.         tmp->head = head, prev->more = tmp;
  1271.       prev = tmp;
  1272.     }
  1273.     head->direction = dir;
  1274.     insert_ob_in_map(head, op->map);
  1275.     if (!QUERY_FLAG(head, FLAG_FREED) && at->randomitems != NULL) {
  1276.       object *tmp;
  1277.       create_treasure(at->randomitems,head,GT_INVENTORY,6,0);
  1278.       for(tmp = head->inv; tmp != NULL; tmp = tmp->below)
  1279.         if(!tmp->nrof)
  1280.           SET_FLAG(tmp, FLAG_NO_DROP);
  1281.     }
  1282.     dir = absdir(dir + 1);
  1283.     if (arch_blocked(at,op->map, op->x + freearr_x[dir],
  1284.                      op->y + freearr_y[dir]))
  1285.     {
  1286.       if (i < number) {
  1287.         new_draw_info(NDI_UNIQUE, 0,op, "There is something in the way,");
  1288.         new_draw_info(NDI_UNIQUE, 0,op, "no more pets for this casting.");
  1289.         if (item != spellNormal) {
  1290.           /* op->stats.sp += (5 + 12 * level + op->level) / (number - i); */ 
  1291.           op->stats.sp += (5 + 12 * level + SK_level(op)) / (number - i);
  1292.           if (op->stats.sp < 0)
  1293.             op->stats.sp = 0;
  1294.         }
  1295.         return 1;
  1296.       }
  1297.     }
  1298.   }
  1299.   if (item != spellNormal && op->stats.sp < 0)
  1300.     op->stats.sp = 0;
  1301.   return 1;
  1302. }
  1303.  
  1304. int create_bomb(object *op,int dir,char *name) {
  1305.   object *tmp;
  1306.   int dx=op->x+freearr_x[dir],dy=op->y+freearr_y[dir];
  1307.   if(wall(op->map,dx,dy)) {
  1308.     new_draw_info(NDI_UNIQUE, 0,op,"There is something in the way.");
  1309.     return 0;
  1310.   }
  1311.   tmp=get_archetype(name);
  1312.  
  1313.   /*  level dependencies for bomb  */
  1314.   tmp->stats.dam=SP_PARAMETERS[SP_BOMB].bdam + SP_level_dam_adjust(op,SP_BOMB);
  1315.   tmp->stats.hp=SP_PARAMETERS[SP_BOMB].bdur + SP_level_strength_adjust(op,SP_BOMB);
  1316.  
  1317.   set_owner(tmp,op);
  1318.   tmp->x=dx,tmp->y=dy;
  1319.   insert_ob_in_map(tmp,op->map);
  1320.   return 1;
  1321. }
  1322.  
  1323. void animate_bomb(object *op) {
  1324.   int i;
  1325.   object *env;
  1326.   archetype *at = find_archetype("splint");
  1327.   if(op->state!=op->arch->animations-1)
  1328.     return;
  1329.   for(env=op;env->env!=NULL;env=env->env);
  1330.   if (op->env) {
  1331.     if (op->type==PLAYER) drop(env,op);
  1332.     else {
  1333.         remove_ob(op);
  1334.         insert_ob_in_map(op, env->map);
  1335.     }
  1336.   }
  1337.   if (env->map == NULL)
  1338.     return;
  1339.   if (at)
  1340.     for(i=1;i<9;i++)
  1341.       fire_arch(op,i,at,0,0);
  1342.   remove_ob(op);
  1343.   op->x=env->x;
  1344.   op->y=env->y;
  1345.   if(!explode_object(op)) /* Boom 8) */
  1346.     LOG(llevError,"Error: bomb refused to go off.\n");
  1347.   return;
  1348. }
  1349.  
  1350.  
  1351. int fire_cancellation(object *op,int dir,archetype *at, int magic) {
  1352.   object *tmp;
  1353.   if(at==NULL)
  1354.     return 0;
  1355.   tmp=arch_to_object(at);
  1356.   if(tmp==NULL)
  1357.     return 0;
  1358.   tmp->x=op->x,tmp->y=op->y;
  1359.   tmp->direction=dir;
  1360.   if(magic)
  1361.     tmp->attacktype|=AT_MAGIC;
  1362.   set_owner(tmp,op);
  1363.   if(op->type==PLAYER)
  1364.     D_LOCK(op);
  1365.   insert_ob_in_map(tmp,op->map);
  1366.   move_cancellation(tmp);
  1367.   if(op->type==PLAYER)
  1368.     D_UNLOCK(op);
  1369.   return 1;
  1370. }
  1371.  
  1372. void move_cancellation(object *op) {
  1373.   remove_ob(op);
  1374.   op->x+=DIRX(op),op->y+=DIRY(op);
  1375.   if(!op->direction||wall(op->map,op->x,op->y)) {
  1376.     free_object(op);
  1377.     return;
  1378.   }
  1379.   if(reflwall(op->map,op->x,op->y)) {
  1380.  
  1381.     op->direction=absdir(op->direction+4);
  1382.     insert_ob_in_map(op,op->map);
  1383.     return;
  1384.   }
  1385.   hit_map(op, 0, op->attacktype);
  1386.   insert_ob_in_map(op,op->map);
  1387. }
  1388.  
  1389. void cancellation(object *op)
  1390. {
  1391.   object *tmp;
  1392.  
  1393.   if(QUERY_FLAG(op, FLAG_ALIVE)||op->type == CONTAINER) {
  1394.     /* Recur through the inventory */
  1395.     for(tmp=op->inv;tmp!=NULL;tmp=tmp->below)
  1396.       if (!did_make_save_item(tmp, AT_CANCELLATION))
  1397.     cancellation(tmp);
  1398.     if(op->type==PLAYER && op->contr->eric_server <= 0) {
  1399.       draw_inventory(op);
  1400.       draw_look(op);
  1401.       fix_player(op);    /* Remember that wc/dam has probably changed */
  1402.     }
  1403.   }
  1404.   else                /* Nullify this object. */
  1405.     if(FABS(op->magic)<=(RANDOM()%6)) {
  1406.       op->magic=0;
  1407.       CLEAR_FLAG(op, FLAG_DAMNED);
  1408.       CLEAR_FLAG(op, FLAG_CURSED);
  1409.       CLEAR_FLAG(op, FLAG_KNOWN_MAGICAL);
  1410.       CLEAR_FLAG(op, FLAG_KNOWN_CURSED);
  1411.       if (op->env && op->env->type == PLAYER)
  1412.     if (op->env->contr->eric_server > 0) 
  1413.         esrv_send_item (op->env, op);
  1414.     else
  1415.         draw_inventory(op->env);
  1416.     }
  1417. }
  1418.  
  1419.  
  1420. /* Create a missile (nonmagic - magic +4). Will either create bolts or arrows
  1421.  * based on whether a crossbow or bow is equiped. If neither, it defaults to
  1422.  * arrows.
  1423.  * Sets the plus based on the casters level. It is also settable with the
  1424.  * invoke command. If the caster attempts to create missiles with too
  1425.  * great a plus, the default is used.
  1426.  * The # of arrows create also goes up with level, so if a 30th level mage
  1427.  * wants LOTS of arrows, and doesn't care what the plus is he could
  1428.  * create nonnmagic arrows, or even -1, etc...
  1429.  *
  1430.  * Written by Ben Fennema (huma@netcom.com)
  1431.  */
  1432.  
  1433. int cast_create_missile(object *op, int dir, char *stringarg)
  1434. {
  1435.   int missile_plus=0, missile_nrof;
  1436.   char *missile_name = NULL;
  1437.   object *tmp, *missile=NULL, *weap=NULL;
  1438.  
  1439.   for (tmp=op->inv; tmp != NULL; tmp=tmp->below)
  1440.     if (tmp->type == BOW && QUERY_FLAG(tmp, FLAG_APPLIED))
  1441.       weap= tmp;
  1442.  
  1443.   if (weap==NULL) missile_name = "arrow";
  1444.   else if (!strcmp(weap->race,"arrows")) missile_name="arrow";
  1445.   else missile_name = "bolt";
  1446.  
  1447.   if (stringarg)
  1448.     missile_plus = atoi(stringarg);
  1449.   if (!stringarg || ((1 + SP_level_strength_adjust(op, SP_CREATE_MISSILE)) -
  1450.                      (3 * missile_plus)) < 0)
  1451.     missile_plus = SP_PARAMETERS[SP_CREATE_MISSILE].bdam +
  1452.                    SP_level_dam_adjust(op, SP_CREATE_MISSILE);
  1453.   if (missile_plus > 4)
  1454.     missile_plus = 4;
  1455.   else if (missile_plus < -4)
  1456.     missile_plus = -4;
  1457.   missile_nrof = SP_PARAMETERS[SP_CREATE_MISSILE].bdur *
  1458.                  ((1 + SP_level_strength_adjust(op, SP_CREATE_MISSILE)) -
  1459.                   (3 * missile_plus));
  1460.   if (find_archetype(missile_name)==NULL) {
  1461.     LOG(llevDebug, "Cast create_missile: could not find archtype %s\n", missile_name);
  1462.     return 0;
  1463.   }
  1464.   missile = get_archetype(missile_name);
  1465.   missile->nrof = missile_nrof;
  1466.   missile->magic = missile_plus;
  1467.   missile->value=0;
  1468.   SET_FLAG(missile, FLAG_IDENTIFIED);
  1469.   if (!cast_create_obj(op,missile,dir) && op->type==PLAYER)
  1470.     pick_up(op, missile);
  1471.   return 1;
  1472. }
  1473.  
  1474.  
  1475. /* Alchemy code by Mark Wedel (master@rahul.net)
  1476.  *
  1477.  * This code adds a new spell, called alchemy.  Alchemy will turn
  1478.  * objects to gold nuggets, the value of the gold nuggets being
  1479.  * about 90% of that of the item itself.  It uses the value of the
  1480.  * object before charisma adjustments, because the nuggets themselves
  1481.  * will be will be adjusted by charisma when sold.
  1482.  *
  1483.  * Large nuggets are worth 25 gp each (base).  You will always get
  1484.  * the maximum number of large nuggets you could get.
  1485.  * Small nuggets are worth 1 gp each (base).  You will get from 0
  1486.  * to the max amount of small nuggets as you could get.
  1487.  *
  1488.  * For example, if an item is worth 110 gold, you will get
  1489.  * 4 large nuggets, and from 0-10 small nuggets.
  1490.  *
  1491.  * There is also a chance (1:30) that you will get nothing at all
  1492.  * for the object.  There is also a maximum weight that will be
  1493.  * alchemied.
  1494.  */
  1495.  
  1496. /* I didn't feel like passing these as arguements to the
  1497.  * two functions that need them.  Real values are put in them
  1498.  * when the spell is cast, and these are freed when the spell
  1499.  * is finished.
  1500.  */
  1501. static object *small, *large;
  1502.  
  1503. static void alchemy_object(object *obj, int *small_nuggets,
  1504.      int *large_nuggets, int *weight)
  1505. {
  1506.     int    value=query_cost(obj, NULL, F_TRUE);
  1507.  
  1508.     /* Give half price when we alchemy money (This should hopefully
  1509.      * make it so that it isn't worth it to alchemy money, sell
  1510.      * the nuggets, alchemy the gold from that, etc.
  1511.      * Otherwise, give 9 silver on the gold for other objects,
  1512.      * so that it would still be more affordable to haul
  1513.      * the stuff back to town.
  1514.      */
  1515.     if (QUERY_FLAG(obj, FLAG_UNPAID))
  1516.     value=0;
  1517.     else if (obj->type==MONEY || obj->type==GEM)
  1518.     value /=3;
  1519.     else if (QUERY_FLAG(obj,FLAG_UNPAID)) value=0;
  1520.     else
  1521.     value *= 0.9;
  1522.  
  1523.     if ((obj->value>0) && RANDOM()%30) {
  1524. #ifdef LOSSY_ALCHEMY
  1525.     int tmp = (value % large->value) / small->value;
  1526.  
  1527.     *large_nuggets += value/ large->value;
  1528.     if (tmp)
  1529.         *small_nuggets += RANDOM() % (tmp + 1);
  1530. #else
  1531.     static int value_store;
  1532.     int count;
  1533.     value_store += value;
  1534.     count = value_store / large->value;
  1535.     *large_nuggets += count;
  1536.     value_store -= count * large->value;
  1537.     count = value_store / small->value;
  1538.     *small_nuggets += count;
  1539.     value_store -= count * small->value;
  1540.     /* LOG(llevDebug, "alchemize value %d, remainder %d\n", value, value_store); */
  1541. #endif
  1542.     }
  1543.  
  1544.     /* Turn 25 small nuggets into 1 large nugget.  If the value
  1545.      * of large nuggets is not evenly divisable my the small nugget
  1546.      * value, take off an extra small_nugget (Assuming small_nuggets!=0)
  1547.      */
  1548.     if (*small_nuggets * small->value >= large->value) {
  1549.     (*large_nuggets)++;
  1550.     *small_nuggets -= large->value / small->value;
  1551.     if (*small_nuggets && large->value % small->value)
  1552.         (*small_nuggets)--;
  1553.     }
  1554.     weight += obj->weight;
  1555.     remove_ob(obj);
  1556.     free_object(obj);
  1557. }
  1558.  
  1559. static void update_map(object *op, int small_nuggets, int large_nuggets,
  1560.     int x, int y)
  1561. {
  1562.     object *tmp;
  1563.  
  1564.     if (small_nuggets) {
  1565.         tmp = get_object();
  1566.         copy_object(small, tmp);
  1567.         tmp-> nrof = small_nuggets;
  1568.         tmp->x = x;
  1569.         tmp->y = y;
  1570.         insert_ob_in_map(tmp, op->map);
  1571.     }
  1572.     if (large_nuggets) {
  1573.         tmp = get_object();
  1574.         copy_object(large, tmp);
  1575.         tmp-> nrof = large_nuggets;
  1576.         tmp->x = x;
  1577.         tmp->y = y;
  1578.         insert_ob_in_map(tmp, op->map);
  1579.     }
  1580. }
  1581.  
  1582. int alchemy(object *op)
  1583. {
  1584.     int x,y,weight=0,weight_max,large_nuggets,small_nuggets;
  1585.     object *next,*tmp;
  1586.  
  1587.   if(op->type!=PLAYER)
  1588.     return 0;
  1589.   /* Put a maximum weight of items that can be alchemied.  Limits the power
  1590.    * some, and also prevents people from alcheming every table/chair/clock
  1591.    * in sight
  1592.    */
  1593.   /* weight_max = 100000 + 50000*op->level; */
  1594.   weight_max = 100000 + 50000*SK_level(op);
  1595.   small=get_archetype("smallnugget"),
  1596.   large=get_archetype("largenugget");
  1597.   for(y= op->y-1;y<=op->y+1;y++) {
  1598.     for(x= op->x-1;x<=op->x+1;x++) {
  1599.       if(out_of_map(op->map,x,y) || wall(op->map,x,y) ||
  1600.      blocks_view(op->map,x,y))
  1601.         continue;
  1602.  
  1603.       small_nuggets=0;
  1604.       large_nuggets=0;
  1605.  
  1606.     for(tmp=get_map_ob(op->map,x,y);tmp!=NULL;tmp=next) {
  1607.           next=tmp->above;
  1608.       if (tmp->weight>0 && !QUERY_FLAG(tmp, FLAG_NO_PICK)
  1609.           && !QUERY_FLAG(tmp, FLAG_ALIVE)) {
  1610.         if(QUERY_FLAG(tmp,FLAG_IS_CAULDRON)) {
  1611. #ifdef ALCHEMY
  1612.         attempt_do_alchemy(op, tmp);
  1613. #endif
  1614.         continue;
  1615.         }
  1616.         if (tmp->inv) {
  1617.         object *next1,*tmp1;
  1618.         for (tmp1 = tmp->inv; tmp1!=NULL; tmp1=next1) {
  1619.             next1 = tmp1->below;
  1620.             if (tmp1->weight>0 && !QUERY_FLAG(tmp1, FLAG_NO_PICK) && !QUERY_FLAG(tmp1, FLAG_ALIVE))
  1621.                 alchemy_object(tmp1, &small_nuggets, &large_nuggets,
  1622.                &weight);
  1623.         }
  1624.         }
  1625.         alchemy_object(tmp, &small_nuggets, &large_nuggets, &weight);
  1626.         
  1627.         if (weight>weight_max) {
  1628.         update_map(op, small_nuggets, large_nuggets, x, y);
  1629.         free_object(large);
  1630.         free_object(small);
  1631.         return 1;
  1632.         }
  1633.       }
  1634.     }
  1635. /* Insert all the nuggets at one time.  This probably saves time, but
  1636.  * it also prevents us from alcheming nuggets that were just created
  1637.  * with this spell.
  1638.  */
  1639.     update_map(op, small_nuggets, large_nuggets, x, y);
  1640.     }
  1641.   }
  1642.   free_object(large);
  1643.   free_object(small);
  1644.   return 1;
  1645. }
  1646.  
  1647. int remove_curse(object *op, int type, SpellTypeFrom src) {
  1648.   object *tmp;
  1649.   int success = 0, was_one = 0;
  1650.  
  1651.   for (tmp = op->inv; tmp; tmp = tmp->below)
  1652.     if (QUERY_FLAG(tmp, FLAG_APPLIED) && (QUERY_FLAG(tmp, FLAG_CURSED) ||
  1653.     (type == SP_REMOVE_DAMNATION && QUERY_FLAG(tmp, FLAG_DAMNED))))
  1654.     {
  1655.       was_one++;
  1656.       /* if (tmp->level <= op->level) */ 
  1657.       if (tmp->level <= SK_level(op))
  1658.       {
  1659.         success++;
  1660.         if (type == SP_REMOVE_DAMNATION)
  1661.       CLEAR_FLAG(tmp, FLAG_DAMNED);
  1662.  
  1663.         CLEAR_FLAG(tmp, FLAG_CURSED);
  1664.         CLEAR_FLAG(tmp, FLAG_KNOWN_CURSED);
  1665.         tmp->value = 0; /* Still can't sell it */
  1666.     if (op->type == PLAYER && op->contr->eric_server > 0)
  1667.         esrv_send_item(op, tmp);
  1668.       }
  1669.     }
  1670.   if (op->type==PLAYER) {
  1671.     if (success) {
  1672.       new_draw_info(NDI_UNIQUE, 0,op, "You feel like someone is helping you.");
  1673.       draw_inventory(op);
  1674.     } else
  1675.       if (was_one)
  1676.         new_draw_info(NDI_UNIQUE, 0,op, "You failed to remove the curse.");
  1677.       else if (src == spellNormal)
  1678.         new_draw_info(NDI_UNIQUE, 0,op, "You are not using any cursed items.");
  1679.       else
  1680.         new_draw_info(NDI_UNIQUE, 0,op, "You hear manical laughter in the distance.");
  1681.   }
  1682.   return success;
  1683. }
  1684.  
  1685.  
  1686. int cast_identify(object *op) {
  1687.   object *tmp;
  1688.   int success = 0, random_val=0;
  1689.   int chance = 8 + op->stats.luck + op->stats.Wis;
  1690.  
  1691.   if (chance < 1)
  1692.     chance = 1;
  1693.  
  1694.   for (tmp = op->inv; tmp ; tmp = tmp->below)
  1695.     if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED) && !tmp->invisible &&
  1696.      need_identify(tmp))
  1697.     {
  1698.       identify(tmp);
  1699.       if (op->type==PLAYER) {
  1700.  
  1701.     new_draw_info_format(NDI_UNIQUE, 0, op,
  1702.         "You have %s.", long_desc(tmp));
  1703.     if (tmp->msg) {
  1704.       new_draw_info(NDI_UNIQUE, 0,op, "The item has a story:");
  1705.       new_draw_info(NDI_UNIQUE, 0,op, tmp->msg);
  1706.     }
  1707.     if (op->contr->eric_server > 0)
  1708.         esrv_send_item(op, tmp);
  1709.       }
  1710.  
  1711.       if ((random_val=RANDOM()%chance) > (chance - ++success - 2))
  1712.         break;
  1713.     }
  1714.   /* If all the power of the spell has been used up, don't go and identify
  1715.    * stuff on the floor.  Only identify stuff on the floor if the spell
  1716.    * was not fully used.
  1717.    */
  1718.   if (random_val<=chance - success -2) {
  1719.     for(tmp = get_map_ob(op->map,op->x,op->y);tmp!=NULL;tmp=tmp->above)
  1720.     if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED) && !tmp->invisible &&
  1721.     need_identify(tmp))
  1722.     {
  1723.       identify(tmp);
  1724.       if (op->type==PLAYER) {
  1725.     new_draw_info_format(NDI_UNIQUE, 0,op,
  1726.         "On the ground is %s.", long_desc(tmp));
  1727.     if (tmp->msg) {
  1728.       new_draw_info(NDI_UNIQUE, 0,op, "The item has a story:");
  1729.       new_draw_info(NDI_UNIQUE, 0,op, tmp->msg);
  1730.     }
  1731.     if (op->contr->eric_server > 0)
  1732.         esrv_send_item(op, tmp);
  1733.       }
  1734.       if (RANDOM() %chance > (chance - ++success - 2))
  1735.     break;
  1736.     }
  1737.   }
  1738.   if (!success)
  1739.     new_draw_info(NDI_UNIQUE, 0,op, "You can't reach anything unidentified.");
  1740.   else {
  1741.     spell_effect(SP_IDENTIFY, op->x, op->y, op->map);
  1742.     if (op->type == PLAYER && op->contr->eric_server <= 0)
  1743.       draw_inventory(op);
  1744.   }
  1745.   return success;
  1746. }
  1747.  
  1748. int cast_detection(object *op, int type) {
  1749.   object *tmp;
  1750.   int x,y,done_one;
  1751.   archetype *detect_arch;
  1752.  
  1753.   detect_arch = find_archetype("detect_magic");
  1754.   if (detect_arch == (archetype *) NULL)
  1755.   {
  1756.     LOG(llevError, "Couldn't find archetype detect_magic.\n");
  1757.     return 0;
  1758.   }
  1759.  
  1760.   for (x = op->x + WINLEFT; x <= op->x + WINRIGHT; x++)
  1761.     for (y = op->y + WINUPPER; y <= op->y + WINLOWER; y++) {
  1762.       if (out_of_map(op->map, x, y))
  1763.         continue;
  1764.       done_one = 0;
  1765.       for (tmp = get_map_ob(op->map, x, y); tmp &&
  1766.         (!done_one || type==SP_DETECT_MAGIC || type==SP_DETECT_CURSE);
  1767.           tmp = tmp->above)
  1768.       {
  1769.         switch(type) {
  1770.         case SP_DETECT_MAGIC:
  1771.           if (!QUERY_FLAG(tmp,FLAG_KNOWN_MAGICAL) && !QUERY_FLAG(tmp, FLAG_IDENTIFIED) &&
  1772.         (is_magical(tmp) || always_magical(tmp))) {
  1773.             SET_FLAG(tmp,FLAG_KNOWN_MAGICAL);
  1774.             if(tmp->type==RUNE) /*peterm:  make runes more visible*/
  1775.                 if(tmp->attacktype&AT_MAGIC)  /* if they're magic! */
  1776.                        tmp->stats.Cha/=4;
  1777.             done_one = 1;
  1778.           }
  1779.           break;
  1780.         case SP_DETECT_MONSTER:
  1781.           if (op->type == PLAYER)
  1782.             done_one = QUERY_FLAG(tmp, FLAG_MONSTER);
  1783.           else
  1784.             done_one = (tmp->type == PLAYER);
  1785.           break;
  1786.         case SP_DETECT_EVIL:
  1787.           if (op->type == PLAYER)
  1788.             done_one = (QUERY_FLAG(tmp, FLAG_MONSTER)&&
  1789.         !QUERY_FLAG(tmp, FLAG_UNAGGRESSIVE)&&
  1790.         !QUERY_FLAG(tmp, FLAG_FRIENDLY));
  1791.           else
  1792.             done_one = (tmp->type == PLAYER);
  1793.           break;
  1794.         case SP_SHOW_INVIS:
  1795.             done_one = tmp->invisible;
  1796.         /* if(RANDOM()%(op->level) > tmp->level/4) tmp->invisible=0; */ 
  1797.         if(RANDOM()%(SK_level(op)) > tmp->level/4) tmp->invisible=0;
  1798.           break;
  1799.         case SP_DETECT_CURSE:
  1800.           if (!QUERY_FLAG(tmp, FLAG_KNOWN_CURSED) &&
  1801.          (QUERY_FLAG(tmp, FLAG_CURSED) ||
  1802.          QUERY_FLAG(tmp, FLAG_DAMNED))) {
  1803.         SET_FLAG(tmp, FLAG_KNOWN_CURSED);
  1804.             done_one = 1;
  1805.           }
  1806.           break;
  1807.         }
  1808.       } /* Done all the object on this square */
  1809.       if (done_one) {
  1810.           object *detect_ob = arch_to_object(detect_arch);
  1811.           detect_ob->x = x;
  1812.           detect_ob->y = y;
  1813.           insert_ob_in_map(detect_ob, op->map);
  1814.       }
  1815.     }
  1816.   if ((type == SP_DETECT_MAGIC || type == SP_DETECT_CURSE) &&
  1817.       op->type == PLAYER)
  1818.   {
  1819.     done_one = 0;
  1820.     for (tmp = op->inv; tmp; tmp = tmp->below)
  1821.       if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED))
  1822.         switch(type) {
  1823.         case SP_DETECT_MAGIC:
  1824.           if (is_magical(tmp) && !QUERY_FLAG(tmp,FLAG_KNOWN_MAGICAL)) {
  1825.             SET_FLAG(tmp,FLAG_KNOWN_MAGICAL);
  1826.         if (op->contr->eric_server > 0)
  1827.         esrv_send_item (op, tmp);
  1828.             done_one = 1;
  1829.           }
  1830.           break;
  1831.         case SP_DETECT_CURSE:
  1832.           if (!QUERY_FLAG(tmp, FLAG_KNOWN_CURSED) &&
  1833.          (QUERY_FLAG(tmp, FLAG_CURSED) ||
  1834.          QUERY_FLAG(tmp, FLAG_DAMNED))) {
  1835.         SET_FLAG(tmp, FLAG_KNOWN_CURSED);
  1836.         if (op->contr->eric_server > 0)
  1837.         esrv_send_item (op, tmp);
  1838.             done_one = 1;
  1839.           }
  1840.           break;
  1841.         }
  1842.     if (done_one && op->contr->eric_server <= 0)
  1843.       draw_inventory(op);
  1844.   }
  1845.   return 1;
  1846. }
  1847.  
  1848. /* Shamelessly hacked from PeterM's cast_charm and destruction code 
  1849.  *  - b.t. thomas@nomad.astro.psu.edu         
  1850.  */ 
  1851.  
  1852. /* Changes in the spell code to make it more powerfull - now it can 
  1853.  * pacify multi-square creatures, and has greater range - Aug 95 b.t. 
  1854.  */
  1855. /* New modification -- w/ Multigod hack, now if its a member of an aligned
  1856.  * race, we automatically pacify it. b.t.
  1857.  */ 
  1858.  
  1859. int cast_pacify(object *op, object *weap, archetype *arch,int spellnum ) {
  1860.   int i,r,j; 
  1861.   object *tmp,*effect;
  1862. #ifdef MULTIPLE_GODS
  1863.   int godnr = get_god(op);
  1864. #endif
  1865.   
  1866.   r= 1 + SP_level_strength_adjust(op,SP_PACIFY);
  1867.  
  1868.   for(i= -r;i<r;i++)
  1869.     for(j= -r;j<r;j++) {
  1870.       if(out_of_map(op->map,op->x+i,op->y+j))
  1871.         continue;
  1872.       for(tmp=get_map_ob(op->map,op->x+i,op->y+j);
  1873.             tmp&&(!QUERY_FLAG(tmp,FLAG_MONSTER));tmp=tmp->above);
  1874.         if(!tmp) continue;
  1875.         if(tmp->type==PLAYER) continue;
  1876.  
  1877. #ifdef MULTIPLE_GODS /* we only go through checking if the monster is not aligned 
  1878.     member, we dont worship a god, or monster has no race */ 
  1879.         if(!tmp->race||godnr==-1
  1880.           ||!strstr(Gods[godnr].aligned_race,tmp->race)) {
  1881. #endif
  1882.           if(tmp->immune&AT_MAGIC||tmp->immune&AT_GODPOWER) continue;
  1883.     /* multiple square monsters only when caster is => level of creature */
  1884.           if((tmp->more || tmp->head) && (SK_level(op) < tmp->level)) continue;  
  1885.       if(weap->slaying)         /* selective pacify */ 
  1886.         if(tmp->race != weap->slaying && tmp->name != weap->slaying) continue;
  1887.         /* if(op->level <( (RANDOM()%(2*tmp->level+1))-(op->stats.Cha-10)/2)) continue; */ 
  1888.           if(SK_level(op) <( (RANDOM()%(2*tmp->level+1))-(op->stats.Cha-10)/2)) continue;
  1889. #ifdef MULTIPLE_GODS
  1890.         }
  1891. #endif
  1892.         if((effect=get_archetype("detect_magic"))){
  1893.                 effect->x = tmp->x;
  1894.                 effect->y = tmp->y;
  1895.                 insert_ob_in_map(effect,tmp->map);
  1896.         }
  1897.         SET_FLAG(tmp,FLAG_UNAGGRESSIVE);
  1898.   }      
  1899.  
  1900.   return 1;
  1901. }
  1902.  
  1903. /* summon fog code. I could'nt decide whether this
  1904.  * could just go into another routine (like create_
  1905.  * the_feature) or have it alone. For now, its separate
  1906.  * function. This code just creates a variable amount of
  1907.  * fog archetypes around the character.
  1908.  * Implementation by b.t. (thomas@nomad.astro.psu.edu)
  1909.  * (based on create bomb code)
  1910.  */
  1911.  
  1912. int summon_fog(object *op, int dir,int spellnum) { 
  1913.   object *tmp;
  1914.   int i,dx=op->x+freearr_x[dir],dy=op->y+freearr_y[dir];
  1915.  
  1916.   if (!spellarch[spellnum])
  1917.     return 0;
  1918.  
  1919.   for(i=1;i<MIN(2+SP_level_strength_adjust(op,spellnum),SIZEOFFREE);i++) {
  1920.  
  1921.      if(wall(op->map,dx,dy)) {
  1922.         new_draw_info(NDI_UNIQUE, 0,op,"There is something in the way.");
  1923.         return 0;
  1924.      }
  1925.      tmp=get_archetype(spellarch[spellnum]->name);
  1926.      tmp->x=dx,tmp->y=dy;    /* all fog starts in 1 place */ 
  1927. #ifdef WALL_CREDIT              /* does someone get exp for the kills? */ 
  1928.      set_owner(tmp,op);        /* note however, that after 'fog' moves */ 
  1929.                 /* it is no longer owned. It is unlikely */
  1930.                 /* that players will garner much exp with */
  1931.                 /* this spell */
  1932. #endif
  1933.      insert_ob_in_map(tmp,op->map);
  1934.   }
  1935.  
  1936.   return 1;
  1937.  
  1938. }
  1939.  
  1940. /*  create_the_feature:  peterm  */
  1941. /*  implementation of the spells which build directors, lightning
  1942.     walls, bullet walls, and fireballwalls.  */
  1943.  
  1944. int create_the_feature(object *op, int dir, int spell_effect)
  1945. {
  1946.   object *tmp=NULL;
  1947.   char buf1[20];
  1948.   int putflag=0;
  1949.   if(!dir) dir=op->facing; else putflag=1;
  1950.   switch(spell_effect) {
  1951.     case SP_BUILD_DIRECTOR:
  1952.       sprintf(buf1,"director_%d",dir);
  1953.     tmp=get_archetype(buf1);
  1954.     SET_FLAG(tmp, FLAG_IS_USED_UP);
  1955.         tmp->stats.food=SP_PARAMETERS[spell_effect].bdur+10*SP_level_strength_adjust(op,spell_effect);
  1956.         tmp->stats.hp=SP_PARAMETERS[spell_effect].bdam+5*SP_level_dam_adjust(op,spell_effect);
  1957.     tmp->stats.maxhp=tmp->stats.hp;
  1958.     break;
  1959.     case SP_BUILD_LWALL:
  1960.       sprintf(buf1,"lightningwall_%d",dir);
  1961.     tmp=get_archetype(buf1);
  1962.     SET_FLAG(tmp, FLAG_IS_USED_UP);
  1963.     SET_FLAG(tmp, FLAG_TEAR_DOWN);
  1964.     SET_FLAG(tmp, FLAG_ALIVE);
  1965.         tmp->stats.food=SP_PARAMETERS[spell_effect].bdur+10*SP_level_strength_adjust(op,spell_effect);
  1966.         tmp->stats.hp=SP_PARAMETERS[spell_effect].bdam+5*SP_level_dam_adjust(op,spell_effect);
  1967.     tmp->stats.maxhp=tmp->stats.hp;
  1968.     break;
  1969.     case SP_BUILD_BWALL:
  1970.       sprintf(buf1,"lbulletwall_%d",dir);
  1971.     tmp=get_archetype(buf1);
  1972.     SET_FLAG(tmp, FLAG_IS_USED_UP);
  1973.     SET_FLAG(tmp, FLAG_TEAR_DOWN);
  1974.     SET_FLAG(tmp, FLAG_ALIVE);
  1975.         tmp->stats.food=SP_PARAMETERS[spell_effect].bdur+10*SP_level_strength_adjust(op,spell_effect);
  1976.         tmp->stats.hp=SP_PARAMETERS[spell_effect].bdam+5*SP_level_dam_adjust(op,spell_effect);
  1977.     tmp->stats.maxhp=tmp->stats.hp;
  1978.     break;
  1979.     case SP_BUILD_FWALL:
  1980.       sprintf(buf1,"firewall_%d",dir);
  1981.     tmp=get_archetype(buf1);
  1982.     SET_FLAG(tmp, FLAG_IS_USED_UP);
  1983.     SET_FLAG(tmp, FLAG_TEAR_DOWN);
  1984.     SET_FLAG(tmp, FLAG_ALIVE);
  1985.         tmp->stats.food=SP_PARAMETERS[spell_effect].bdur+10*SP_level_strength_adjust(op,spell_effect);
  1986.         tmp->stats.hp=SP_PARAMETERS[spell_effect].bdam+5*SP_level_dam_adjust(op,spell_effect);
  1987.     tmp->stats.maxhp=tmp->stats.hp;
  1988.     break;
  1989.   }
  1990. #ifdef WALL_CREDIT
  1991.   set_owner(tmp,op);
  1992. #endif  /* determines whether someone gets credit for kills. */
  1993.   tmp->level=SK_level(op)/2;  /*  so that the spell that the wall casts
  1994.                  inherit part of the effectiveness of
  1995.                  of the wall builder */
  1996.   tmp->x=op->x;tmp->y=op->y;
  1997.   if(putflag) { tmp->x+=freearr_x[dir];tmp->y+=freearr_y[dir];}
  1998.   insert_ob_in_map(tmp,op->map);
  1999.   if(QUERY_FLAG(tmp, FLAG_BLOCKSVIEW))
  2000.     update_all_los(op->map);
  2001.   if(op->type==PLAYER)
  2002.     draw(op);
  2003.   else
  2004.     SET_FLAG(op, FLAG_SCARED); /* We don't want them to walk through the wall! */
  2005.   return 1;
  2006. }
  2007.  
  2008.  
  2009. /*  cast_transfer:  peterm  */
  2010. /*  following spell transfers mana from one person to another.
  2011.     right now, it's no respecter of maximum sp limits.  WOn't
  2012.     fix that, regard it as a feature.  be nice to make someone's
  2013.     head explode if they supercharge too much, though.  */
  2014.  
  2015. int cast_transfer(object *op,int dir) {
  2016.     object *plyr;
  2017. /*  see if we can find someone to give sp to.  */
  2018.      for(plyr=get_map_ob(op->map,op->x+freearr_x[dir],op->y+freearr_y[dir]);
  2019.      plyr!=NULL;
  2020.      plyr=plyr->above)
  2021.     if(QUERY_FLAG(plyr, FLAG_ALIVE))
  2022.         break;
  2023.      /*  If we did not find a player in the specified direction, transfer
  2024.     to anyone on top of us. */
  2025.     if(plyr==NULL)
  2026.          for(plyr=get_map_ob(op->map,op->x,op->y); plyr!=NULL; plyr=plyr->above)
  2027.     if(QUERY_FLAG(plyr,FLAG_ALIVE))
  2028.         break;
  2029.     if(plyr) {
  2030.     int maxsp=plyr->stats.maxsp;
  2031.     int sp=(plyr->stats.sp+=8);
  2032.  
  2033.     new_draw_info(NDI_UNIQUE, 0,plyr,"You feel energy course through you.");
  2034.     if(sp>=maxsp*2) {
  2035.             new_draw_info(NDI_UNIQUE, 0,plyr,"Your head explodes!");
  2036.             fire_arch (plyr, 0, spellarch[SP_L_FIREBALL], SP_L_FIREBALL, 0);
  2037.                 /* Explodes a large fireball centered at player */
  2038. /*            hit_player(plyr, 9999, op, AT_PHYSICAL);*/
  2039.         plyr->stats.sp = 2*maxsp;
  2040.  
  2041.         }
  2042.         else if(sp>=maxsp*1.88)
  2043.             new_draw_info(NDI_UNIQUE, NDI_ORANGE,plyr,"You feel like your head is going to explode.");
  2044.         else if(sp>=maxsp*1.66)
  2045.             new_draw_info(NDI_UNIQUE, 0,plyr, "You get a splitting headache!");
  2046.         else if(sp>=maxsp*1.5) {
  2047.             new_draw_info(NDI_UNIQUE, 0,plyr,"CHaOs fills your world.");
  2048.         confuse_player(op,op,99);
  2049.     }
  2050.         else if(sp>=maxsp*1.25)
  2051.             new_draw_info(NDI_UNIQUE, 0,plyr,"You start hearing voices.");
  2052.         return 1;
  2053.     }
  2054.     else return 0;
  2055. }
  2056.  
  2057. /*  drain_magic:  peterm  */
  2058. /*  drains all the magic out of the victim.  */
  2059. int drain_magic(object *op,int dir) {
  2060.     object *tmp;
  2061.  
  2062.      for(tmp=get_map_ob(op->map,op->x+freearr_x[dir],op->y+freearr_y[dir]);
  2063.          tmp!=NULL;
  2064.          tmp=tmp->above)
  2065.         if(QUERY_FLAG(tmp, FLAG_ALIVE))
  2066.         break;
  2067.      /*  If we did not find a player in the specified direction, transfer
  2068.     to anyone on top of us. */
  2069.  
  2070.     if(tmp==NULL)
  2071.          for(tmp=get_map_ob(op->map,op->x,op->y); tmp!=NULL; tmp=tmp->above)
  2072.     if(QUERY_FLAG(tmp, FLAG_ALIVE))
  2073.         break;
  2074.  
  2075.  
  2076.       if(tmp&&op!=tmp) { tmp->stats.sp*=0.1; return 1; }
  2077.       else return 0;
  2078. }
  2079.      
  2080. /*  counterspell:  peterm  */
  2081. /*  an object of type counterspell will nullify cone objects,
  2082.     explosion objects, and anything else that |=magic.  */
  2083.  
  2084. void counterspell(object *op)
  2085. {
  2086.     object *tmp;
  2087.     int nflag=0;
  2088.     
  2089.     for(tmp=get_map_ob(op->map,op->x,op->y); tmp!=NULL; tmp=tmp->above,nflag=0)
  2090.     {  if(tmp->material==0 && tmp->attacktype&AT_MAGIC &&!
  2091.     (tmp->attacktype&AT_COUNTERSPELL)) nflag=1;
  2092.     else
  2093.     switch(tmp->type) {
  2094.         case CONE: case FBALL: case LIGHTNING:
  2095.         case FBULLET: case MMISSILE: case SPEEDBALL:
  2096.         case BOMB: case POISONCLOUD: case CANCELLATION:
  2097.         case SWARM_SPELL:
  2098.         case BALL_LIGHTNING:
  2099.         nflag=1;
  2100.         break;
  2101.         case RUNE:
  2102.         nflag=2;
  2103.         break;
  2104.         default:
  2105.         nflag=0;
  2106.     }
  2107.     switch(nflag) {
  2108.         case 1:
  2109.         /* { if(op->level > tmp->level) { */ 
  2110.         { if(SK_level(op) > tmp->level) {
  2111.         remove_ob(tmp);
  2112.         free_object(tmp);
  2113.         }
  2114.         break;
  2115.         }
  2116.         case 2:
  2117.         { if(RANDOM()%150 == 0) {
  2118.         tmp->stats.hp--;  /* weaken the rune */
  2119.         if(!tmp->stats.hp) {
  2120.             remove_ob(tmp);
  2121.             free_object(tmp);
  2122.         }
  2123.         }
  2124.         break;
  2125.         }
  2126.     }
  2127.     }
  2128. }
  2129.  
  2130.  
  2131.  
  2132. /*  peterm:  function which summons hostile monsters and
  2133.   places them in nearby squares.  */
  2134.     
  2135. int summon_hostile_monsters(object *op,int n,char *monstername){
  2136.   int i;
  2137.   for(i=0;i<n;i++)
  2138.     put_a_monster(op,monstername);
  2139.   return n;
  2140. }
  2141.  
  2142.  
  2143. /*  charm spell by peterm@soda.berkeley.edu 
  2144.     searches nearby squares for monsters to charm.  Each of them
  2145.     is subject to being charmed, that is, to becoming the pet
  2146.     monster of the caster.  Monsters larger than 1 square
  2147.     are uncharmeable right now.  */
  2148.  
  2149. /* Aug 95 - hack on the code to make it charm only undead for 
  2150.  * priests, and not charm undead for magicians -b.t
  2151.  */
  2152.  
  2153. int cast_charm(object *op, archetype *arch,int spellnum) {
  2154.   int i;
  2155.   object *tmp,*effect;
  2156.   
  2157.   for(i=1;i<MIN(9+SP_level_strength_adjust(op,spellnum),SIZEOFFREE);i++) {
  2158.     for(tmp=get_map_ob(op->map,op->x+freearr_x[i],op->y+freearr_y[i]);
  2159.         tmp&&(!QUERY_FLAG(tmp,FLAG_MONSTER));tmp=tmp->above);
  2160.     if(!tmp) continue;
  2161.     if(tmp->type==PLAYER) continue;
  2162.     if(tmp->immune & AT_MAGIC) continue;
  2163.     if(QUERY_FLAG(tmp,FLAG_UNDEAD)) continue;
  2164.     if(tmp->more || tmp->head) continue;  /* multiple square monsters NOT */
  2165.     /* if(op->level <( (RANDOM()%(2*tmp->level+1))-(op->stats.Cha-10)/2)) continue; */ 
  2166.     if(SK_level(op) <( (RANDOM()%(2*tmp->level+1))-(op->stats.Cha-10)/2)) continue;
  2167.  
  2168.     if((effect=get_archetype("detect_magic"))){
  2169.         effect->x = tmp->x;
  2170.         effect->y = tmp->y;
  2171.         insert_ob_in_map(effect,tmp->map);
  2172.     }
  2173.     set_owner(tmp,op);
  2174.     SET_FLAG(tmp,FLAG_MONSTER);
  2175.     if(op->type==PLAYER)
  2176.     tmp->stats.exp = 0;
  2177.     SET_FLAG(tmp,FLAG_FRIENDLY);
  2178.     tmp->move_type = PETMOVE;
  2179.   }
  2180.   return 1;
  2181. }
  2182.  
  2183. int cast_charm_undead(object *op, archetype *arch,int spellnum) {
  2184.   int i;
  2185.   object *tmp,*effect;
  2186.  
  2187.   for(i=1;i<MIN(9+SP_level_strength_adjust(op,spellnum),SIZEOFFREE);i++) {
  2188.         for(tmp=get_map_ob(op->map,op->x+freearr_x[i],op->y+freearr_y[i]);
  2189.             tmp&&(!QUERY_FLAG(tmp,FLAG_MONSTER));tmp=tmp->above);
  2190.         if(!tmp) continue;
  2191.         if(tmp->type==PLAYER) continue;
  2192.         if(tmp->immune & AT_MAGIC) continue;
  2193.         if(!QUERY_FLAG(tmp,FLAG_UNDEAD)) continue;
  2194.         if(tmp->more || tmp->head) continue;  /* multiple square monsters NOT */
  2195.         if(SK_level(op) <( (RANDOM()%(2*tmp->level+1))-(op->stats.Cha-10)/2)) continue;
  2196.  
  2197.         if((effect=get_archetype("detect_magic"))){
  2198.                 effect->x = tmp->x;
  2199.                 effect->y = tmp->y;
  2200.                 insert_ob_in_map(effect,tmp->map);
  2201.         }
  2202.         set_owner(tmp,op);
  2203.         SET_FLAG(tmp,FLAG_MONSTER);
  2204.         if(op->type==PLAYER)
  2205.         tmp->stats.exp = 0;
  2206.         SET_FLAG(tmp,FLAG_FRIENDLY);
  2207.         tmp->move_type = PETMOVE;
  2208.   }
  2209.   return 1;
  2210. }
  2211.  
  2212. int summon_cult_monsters(object *op, int dir) {
  2213.   int godnr=get_god(op), raceindex=0, monindex=0, summon_level, number, i;
  2214.   int racenr=0;
  2215.   char *race,*monster,buf[MAX_BUF];
  2216.   archetype *at = NULL;
  2217.  
  2218.   /* find deity */
  2219.   if (godnr<0) {
  2220.      new_draw_info(NDI_UNIQUE, 0,op, "You worship no living deity!");
  2221.      return 0;
  2222.   } else if(!strcmp("none",Gods[godnr].aligned_race)) {
  2223.      new_draw_info(NDI_UNIQUE, 0,op, "Your deity has no creatures that you may summon!");
  2224.      return 0;
  2225.   }
  2226.  
  2227.  
  2228.   /* now determine the number of races available */
  2229.      sprintf(buf,Gods[godnr].aligned_race);
  2230.      race = strtok(buf,","); 
  2231.      while(race) { 
  2232.        racenr++; 
  2233.        race = strtok(NULL,",");  
  2234.      }   
  2235.  
  2236.   /* next, randomly select a race from the aligned_races string */
  2237.      if(racenr>1) { 
  2238.         racenr = RANDOM()%racenr;
  2239.         sprintf(buf,Gods[godnr].aligned_race);
  2240.         race = strtok(buf,",");
  2241.         for(i=0;i<racenr;i++) 
  2242.          race = strtok(NULL,",");
  2243.      } else 
  2244.         race = Gods[godnr].aligned_race;
  2245.  
  2246.  /* see if a we can match a race list of monsters  */
  2247.   for(raceindex=0;raceindex<MAX_RACES;raceindex++)
  2248.       if(!strcmp(race,summoned_monsters[raceindex][0])) break;
  2249.  
  2250.   /* no monsters to summon, goodbye!, this is a safety, shouldnt happen */
  2251.   if(!race||summoned_monsters[monindex][0]=="none") {
  2252.      LOG(llevDebug,"summon_cult_monster() - failed to find requested aligned race\n");
  2253.      new_draw_info(NDI_UNIQUE, 0,op,
  2254.     "The spell fails! Your god's creatures are beyond");
  2255.      new_draw_info(NDI_UNIQUE, 0,op,
  2256.         "the range of your summons.");
  2257.      return 0;
  2258.   }
  2259.  
  2260.   summon_level = RANDOM()%(SK_level(op)+((op->stats.Wis?op->stats.Wis:20)/4));
  2261.  
  2262.   if(op->path_attuned&PATH_SUMMON) summon_level += 5;
  2263.   if(op->path_repelled&PATH_SUMMON) summon_level -= 5;
  2264.  
  2265.   LOG(llevDebug,"summon_cult_mon(): got summon level = %d\n",summon_level);
  2266.  
  2267.   for(monindex=(MAX_RACE_MEMBERS-1);monindex>0;monindex--) {
  2268.      if(!strcmp((monster = summoned_monsters[raceindex][monindex]),"none")) continue;
  2269.      if((at = find_archetype(monster))==NULL) continue;
  2270.      if((at->clone.level<=summon_level)&&!(RANDOM()%2)) break;
  2271.   }
  2272.  
  2273.   LOG(llevDebug," monster level = %d\n",at->clone.level);
  2274.  
  2275.   if(!at||monindex<1||(summon_level<at->clone.level)) {
  2276.        new_draw_info(NDI_UNIQUE, 0,op, "Your deity fails to send anything.");
  2277.        return 0;
  2278.   } 
  2279.  
  2280.   if(at->clone.level>(summon_level/2))
  2281.     number = RANDOM()%2 + 1;
  2282.   else
  2283.     number = RANDOM()%2 + RANDOM()%2 + 2;
  2284.       
  2285.   if (!dir)                               
  2286.     dir = find_free_spot(at, op->map, op->x, op->y, 1, SIZEOFFREE);
  2287.   if(arch_blocked(at,op->map, op->x + freearr_x[dir], op->y+freearr_y[dir]))
  2288.   {  
  2289.     new_draw_info(NDI_UNIQUE, 0,op, "There is something in the way.");
  2290.     if(op->type == PLAYER)
  2291.       op->contr->count_left = 0;
  2292.     return 0;
  2293.   }
  2294.   for (i = 1; i < number + 1; i++) {
  2295.     archetype *atmp;
  2296.     object *prev = NULL, *head = NULL; /* We want to summon dragons *grin* */
  2297.  
  2298.     for(atmp = at; atmp!=NULL; atmp = atmp->more) {
  2299.       object *tmp;
  2300.       tmp = arch_to_object(atmp);
  2301.       if (atmp == at) {
  2302.         set_owner(tmp, op);
  2303.         SET_FLAG(tmp, FLAG_MONSTER);
  2304.         if (op->type == PLAYER) {
  2305.           tmp->stats.exp = 0;
  2306.           add_friendly_object(tmp);
  2307.           SET_FLAG(tmp, FLAG_FRIENDLY);
  2308.           tmp->move_type = PETMOVE;
  2309.         } else
  2310.           if(QUERY_FLAG(op, FLAG_FRIENDLY)) {
  2311.             add_friendly_object(tmp);
  2312.             SET_FLAG(tmp, FLAG_FRIENDLY);
  2313.             tmp->move_type = PETMOVE;
  2314.           } else
  2315.         tmp->speed_left = -1;
  2316.         tmp->enemy = op->enemy;
  2317.         tmp->type = 0;
  2318.       }
  2319.       if(head == NULL)
  2320.         head = tmp;
  2321.       tmp->x = op->x + freearr_x[dir] + tmp->arch->clone.x;
  2322.       tmp->y = op->y + freearr_y[dir] + tmp->arch->clone.y;
  2323.       tmp->map = op->map;
  2324.       if(head != tmp)
  2325.         tmp->head = head, prev->more = tmp;
  2326.       prev = tmp;
  2327.     }
  2328.    head->direction = dir;
  2329.     /* need to change some monster attr to prevent crashing */
  2330.     if(head->attacktype&AT_GHOSTHIT) head->attacktype=(AT_PHYSICAL|AT_DRAIN);
  2331.     if(head->other_arch) head->other_arch=NULL;
  2332.     if(QUERY_FLAG(head,FLAG_CHANGING)) CLEAR_FLAG(head,FLAG_CHANGING);
  2333.     if(QUERY_FLAG(head,FLAG_STAND_STILL)) CLEAR_FLAG(head,FLAG_STAND_STILL);
  2334.     if(QUERY_FLAG(head,FLAG_GENERATOR)) CLEAR_FLAG(head,FLAG_GENERATOR);
  2335.     if(QUERY_FLAG(head,FLAG_SPLITTING)) CLEAR_FLAG(head,FLAG_SPLITTING);
  2336.  
  2337.     /* now, a little bit of tailoring. If the monster is much lower in 
  2338.      * level than the summon_level, we get a better monster */
  2339.  
  2340.     if((head->level+5)<summon_level) { 
  2341.     int ii;
  2342.      char buf[MAX_BUF];
  2343.     for(ii=summon_level-(head->level)-5;ii>0;ii--) {
  2344.         switch(RANDOM()%3+1) {
  2345.         case 1:
  2346.                  head->stats.wc--;
  2347.            break;
  2348.         case 2:
  2349.                head->stats.ac--;
  2350.            break;
  2351.         case 3:
  2352.                head->stats.dam+=3;
  2353.            break;
  2354.         default:
  2355.            break;
  2356.         }
  2357.         head->stats.hp+=3;
  2358.     }
  2359.     head->stats.maxhp=head->stats.hp;
  2360.     if(head->name) { 
  2361.       if(summon_level>30+head->level) 
  2362.          sprintf(buf,"Arch %s of %s",head->name,Gods[godnr].name);
  2363.       else
  2364.          sprintf(buf,"%s of %s",head->name,Gods[godnr].name);
  2365.       free_string(head->name);
  2366.       head->name=add_string(buf);
  2367.     }
  2368.     } 
  2369.  
  2370.     insert_ob_in_map(head, op->map);
  2371.     if (!QUERY_FLAG(head, FLAG_FREED) && at->randomitems != NULL) {
  2372.       object *tmp;
  2373.       create_treasure(at->randomitems,head,GT_INVENTORY,6,0);
  2374.       for(tmp = head->inv; tmp != NULL; tmp = tmp->below)
  2375.         if(!tmp->nrof)
  2376.           SET_FLAG(tmp, FLAG_NO_DROP);
  2377.     }
  2378.     dir = absdir(dir + 1);
  2379.     if (arch_blocked(at,op->map, op->x + freearr_x[dir],
  2380.                      op->y + freearr_y[dir]))
  2381.     {
  2382.       if (i < number) {
  2383.         new_draw_info(NDI_UNIQUE, 0,op, "There is something in the way,");
  2384.         new_draw_info(NDI_UNIQUE, 0,op, "no more monsters for this casting.");
  2385.         return 1;
  2386.       }
  2387.     }
  2388.   }    
  2389.   return 1;
  2390. }  
  2391.  
  2392. /* summon_avatar() - taken from the code which summons golems. We 
  2393.  * cant use because we need to throw in a few extra's here. b.t.
  2394.  */
  2395.  
  2396. int summon_avatar(object *op,int dir, archetype *at, int spellnum) {
  2397.   object *tmp;
  2398. #ifdef MULTIPLE_GODS
  2399.   char buf[MAX_BUF];
  2400.   int godnr=lookup_god_by_name(determine_god(op));
  2401.  
  2402.   if(godnr==-1) {
  2403.         new_draw_info(NDI_UNIQUE, 0,op,
  2404.             "You can't summon if you don't worship a god!");
  2405.         return 0;
  2406.   }
  2407. #endif
  2408.  
  2409.   if(op->type==PLAYER)
  2410.     if(op->contr->golem!=NULL&&!QUERY_FLAG(op->contr->golem,FLAG_FREED)) {
  2411.       control_golem(op->contr->golem,dir);
  2412.       return 0;
  2413.     }
  2414.   if(!dir)
  2415.     dir=find_free_spot(NULL,op->map,op->x,op->y,1,9);
  2416.   if(blocked(op->map,op->x+freearr_x[dir],op->y+freearr_y[dir])) {
  2417.     new_draw_info(NDI_UNIQUE, 0,op,"There is something in the way.");
  2418.     if(op->type==PLAYER)
  2419.       op->contr->count_left=0;
  2420.     return 0;
  2421.   }
  2422.  tmp=arch_to_object(at);
  2423.   if(op->type==PLAYER) {
  2424.     CLEAR_FLAG(tmp, FLAG_MONSTER);
  2425.     tmp->stats.exp=0;
  2426.     add_friendly_object(tmp);
  2427.     tmp->type=GOLEM;
  2428.     set_owner(tmp,op);
  2429.     op->contr->golem=tmp;
  2430.     /* give the player control of the golem */
  2431.     op->contr->shoottype=range_scroll;
  2432.   } else {
  2433.     if(QUERY_FLAG(op, FLAG_FRIENDLY)) {
  2434.       object *owner = get_owner(op);
  2435.       if(owner != NULL) /* For now, we transfer ownership */
  2436.         set_owner(tmp,owner);
  2437.       tmp->move_type = PETMOVE;
  2438.       add_friendly_object(tmp);
  2439.       SET_FLAG(tmp, FLAG_FRIENDLY);
  2440.     }
  2441.     SET_FLAG(tmp, FLAG_MONSTER);
  2442.   }  
  2443.   /*  This sets the level dependencies on dam, wc and hp */
  2444.   tmp->stats.wc -= SP_level_strength_adjust(op,spellnum);
  2445.   if(tmp->stats.wc<-127) tmp->stats.wc = -127;
  2446.   tmp->stats.hp = SP_PARAMETERS[spellnum].bdur +
  2447.                          12 * SP_level_strength_adjust(op,spellnum);
  2448.   tmp->stats.dam= SP_PARAMETERS[spellnum].bdam +(2*SP_level_dam_adjust(op,spellnum));
  2449.   if(tmp->stats.dam<0) tmp->stats.dam=127;  /*seen this go negative!*/
  2450.  
  2451. #ifdef MULTIPLE_GODS /* tailor it to the gods nature */
  2452.     sprintf(buf,"%s of %s",tmp->name,Gods[godnr].name);
  2453.     if(tmp->name) free_string(tmp->name);
  2454.     tmp->name = add_string(buf);
  2455.     tmp->attacktype|=Gods[godnr].attacktype;
  2456.     if(Gods[godnr].vulnerable) tmp->vulnerable|=Gods[godnr].vulnerable;
  2457.     if(Gods[godnr].immune) tmp->immune|=Gods[godnr].immune;
  2458.     if(Gods[godnr].protected) tmp->protected|=Gods[godnr].protected;
  2459.     if(strcmp(Gods[godnr].enemy_race,"none"))
  2460.          tmp->slaying = add_string(Gods[godnr].enemy_race);
  2461. #else
  2462.     tmp->attacktype|=AT_WEAPONMAGIC;
  2463. #endif
  2464.  
  2465.   /*  make experience increase in proportion to the strength of 
  2466.    *  the summoned creature. */
  2467.   tmp->stats.exp *= SP_level_spellpoint_cost(op,spellnum)/spells[spellnum].sp;
  2468.   tmp->speed_left= -1;
  2469.   tmp->x=op->x+freearr_x[dir],tmp->y=op->y+freearr_y[dir];
  2470.   tmp->direction=dir;
  2471.   insert_ob_in_map(tmp,op->map);
  2472.   return 1;
  2473. }
  2474.  
  2475. /* cast_consecrate() - a spell to make an altar your god's */
  2476.  
  2477. int cast_consecrate(object *op) {
  2478.   char buf[MAX_BUF];
  2479.   int success=0;
  2480. #ifdef MULTIPLE_GODS
  2481.   object *tmp;
  2482.   int godnr=lookup_god_by_name(determine_god(op));
  2483. #endif
  2484.   sprintf(buf,"Nothing happens.");
  2485. #ifdef MULTIPLE_GODS
  2486.   if(godnr==-1) {
  2487.         new_draw_info(NDI_UNIQUE, 0,op,
  2488.             "You can't consecrate anything if you don't worship a god!");
  2489.         return 0;
  2490.   }
  2491.  
  2492.   sprintf(buf,"You are'nt standing over an altar!");
  2493.   for(tmp=op->below;tmp;tmp=tmp->below)
  2494.         if(tmp->type==ALTAR) {
  2495.              if(!tmp->title && strcmp(tmp->name,tmp->arch->clone.name)) {
  2496.                  sprintf(buf,"That altar may not be consecrated.");
  2497.                  break;
  2498.              } else if(QUERY_FLAG(tmp,FLAG_IS_FLOOR)) break;
  2499.              if(tmp->title)
  2500.                  free_string(tmp->title);
  2501.              if(tmp->name)
  2502.                  free_string(tmp->name);
  2503.              sprintf(buf,"%s of %s",tmp->arch->clone.name,Gods[godnr].name);
  2504.              tmp->name = add_string(buf);
  2505.              tmp->title = add_string(Gods[godnr].name);
  2506.              sprintf(buf,"You consecrated the altar to %s!",Gods[godnr].name);
  2507.              success = 1;
  2508.          if(op->type==PLAYER) draw_look(op);
  2509.              break;
  2510.         }
  2511. #endif
  2512.  
  2513.    new_draw_info(NDI_UNIQUE, 0,op,buf);
  2514.    return success;
  2515. }
  2516.  
  2517.  
  2518. /* finger_of_death() - boss high-level cleric spell. */
  2519.  
  2520. int finger_of_death(object *caster, int dir) {
  2521.   object *hitter,*target=get_pointed_target(caster,dir);
  2522.   int success = 1;
  2523.  
  2524.   if(!target) {
  2525.         new_draw_info(NDI_UNIQUE,0,caster,"Nothing happens.");
  2526.     return 0;
  2527.   }
  2528.  
  2529.   /* we create a hitter object -- the spell */
  2530.   hitter=get_archetype("face_of_death");
  2531.   hitter->level=SP_PARAMETERS[SP_FINGER_DEATH].bdam + 
  2532.          3*SP_level_dam_adjust(caster,SP_FINGER_DEATH); 
  2533.   if(caster->path_attuned&PATH_DEATH) hitter->level+=5;
  2534.   if(caster->path_repelled&PATH_DEATH) hitter->level-=5;
  2535.   set_owner(hitter,caster);
  2536.   hitter->x=target->x;
  2537.   hitter->y=target->y;
  2538.   hitter->stats.maxhp=hitter->count; /*??*/
  2539.  
  2540.   /* there are 'grave' consequences for using this spell on the unliving! */
  2541.   if(QUERY_FLAG(target,FLAG_UNDEAD)) {
  2542.       success = 0;
  2543.       if(RANDOM()%3) { 
  2544.         new_draw_info(NDI_UNIQUE,0,caster,"Idiot! Your spell boomerangs!");     
  2545.     hitter->x=caster->x;
  2546.     hitter->y=caster->y;    
  2547.       } else { 
  2548.         new_draw_info_format(NDI_UNIQUE,0,caster,"The %s looks stronger!",
  2549.       query_name(target));     
  2550.     target->stats.hp = target->stats.maxhp*2; 
  2551.         free_object(hitter);
  2552.     return 0;    
  2553.       }
  2554.   }  
  2555.  
  2556.   insert_ob_in_map(hitter,caster->map); 
  2557.  
  2558.   return success;
  2559. }
  2560.  
  2561. /* staff_to_snake() - taken from the code which summons golems. We
  2562.  * allow the cleric to create a golem from thier staff. If the staff
  2563.  * is magical, the snake created is enhanced, and vice-versa for 
  2564.  * cursed items!  -b.t.
  2565.  */
  2566.  
  2567. int staff_to_snake(object *op,int dir, archetype *at, int spellnum) {
  2568.   object *weapon, *tmp;
  2569.  
  2570.   if(op->type==PLAYER)
  2571.     if(op->contr->golem!=NULL&&!QUERY_FLAG(op->contr->golem,FLAG_FREED)) {
  2572.       control_golem(op->contr->golem,dir);
  2573.       return 0;
  2574.     }
  2575.   if(!dir) 
  2576.     dir=find_free_spot(NULL,op->map,op->x,op->y,1,9);
  2577.   if(blocked(op->map,op->x+freearr_x[dir],op->y+freearr_y[dir])) {
  2578.     new_draw_info(NDI_UNIQUE, 0,op,"There is something in the way.");
  2579.     if(op->type==PLAYER)
  2580.       op->contr->count_left=0;
  2581.     return 0;
  2582.   }
  2583.  
  2584.  /* need to find the weapon to transform */
  2585.  for(weapon=op->inv;weapon;weapon=weapon->below)
  2586.     if(weapon->type==WEAPON&&QUERY_FLAG(weapon,FLAG_APPLIED)) break;
  2587.  
  2588.  if(!weapon||strcmp(weapon->name,"quarterstaff")) {
  2589.     if(op->type==PLAYER) { 
  2590.       new_draw_info(NDI_UNIQUE, 0,op,"The spell fails to transform your weapon.");
  2591.       op->contr->count_left=0;   
  2592.     }     
  2593.     return 0;
  2594.  } 
  2595.  
  2596.  tmp=arch_to_object(at);
  2597.   if(op->type==PLAYER && !QUERY_FLAG(weapon,FLAG_CURSED) &&
  2598.       !QUERY_FLAG(weapon,FLAG_DAMNED)) {
  2599.     CLEAR_FLAG(tmp, FLAG_MONSTER);
  2600.     tmp->stats.exp=0;
  2601.     add_friendly_object(tmp);
  2602.     tmp->type=GOLEM;
  2603.     set_owner(tmp,op);
  2604.     op->contr->golem=tmp;
  2605.     /* give the player control of the golem */
  2606.     op->contr->shoottype=range_scroll;
  2607.   } else {
  2608.     if(QUERY_FLAG(op, FLAG_FRIENDLY)&&(!QUERY_FLAG(weapon,FLAG_CURSED)||
  2609.         !QUERY_FLAG(weapon,FLAG_DAMNED)) ) {
  2610.       object *owner = get_owner(op);
  2611.       if(owner != NULL) /* For now, we transfer ownership */
  2612.         set_owner(tmp,owner);
  2613.       tmp->move_type = PETMOVE;
  2614.       add_friendly_object(tmp);
  2615.       SET_FLAG(tmp, FLAG_FRIENDLY);
  2616.     } 
  2617.     SET_FLAG(tmp, FLAG_MONSTER);
  2618.   }  
  2619.  
  2620.   /* ok, tailor the serpent's characteristics based on the weapon */
  2621.   tmp->stats.wc = op->stats.wc - SP_level_strength_adjust(op,spellnum);
  2622.   tmp->stats.hp = SP_PARAMETERS[spellnum].bdur +
  2623.                          4 * SP_level_strength_adjust(op,spellnum);
  2624.   tmp->stats.dam = weapon->stats.dam + (2*SP_level_dam_adjust(op,spellnum));
  2625.   if(tmp->stats.dam<0) tmp->stats.dam=127;  /*seen this go negative!*/
  2626.   tmp->attacktype=AT_POISON|AT_PHYSICAL;
  2627.   if(weapon->attacktype) tmp->attacktype=tmp->attacktype|weapon->attacktype;
  2628.   /* magic weapons make boss snakes ! */
  2629.   if(weapon->magic) {
  2630.    int magic = weapon->magic>0 ? weapon->magic : -1*weapon->magic;
  2631.    tmp->speed += 0.05 * magic;
  2632.    tmp->stats.dam *= (1 + magic);
  2633.    tmp->stats.hp *= (1 + magic);
  2634.   }
  2635.   if(weapon->immune) tmp->immune = weapon->immune; 
  2636.   if(weapon->protected) tmp->protected = weapon->protected; 
  2637.   if(weapon->vulnerable) tmp->vulnerable = weapon->vulnerable; 
  2638.   if(weapon->slaying) {
  2639.     if(tmp->slaying) free_string(tmp->slaying);
  2640.     tmp->slaying = add_string(weapon->slaying);
  2641.   }
  2642.  
  2643.   /* now, remove object from op inv, insert into snake */
  2644.  
  2645.   CLEAR_FLAG(weapon,FLAG_APPLIED); 
  2646.   remove_ob(weapon);
  2647.   insert_ob_in_ob(weapon,tmp);
  2648.   fix_player(op);
  2649.   draw_inventory(op);
  2650.   draw_stats(op);
  2651.   new_draw_info(NDI_UNIQUE, 0,op,"Your staff becomes a serpent and leaps to the ground!");
  2652.  
  2653.   /*  make experience increase in proportion to the strength of
  2654.    *  the summoned creature. */
  2655.   tmp->stats.exp *= SP_level_spellpoint_cost(op,spellnum)/spells[spellnum].sp;
  2656.   tmp->speed_left= -1;
  2657.   tmp->x=op->x+freearr_x[dir],tmp->y=op->y+freearr_y[dir];
  2658.   tmp->direction=dir;
  2659.   insert_ob_in_map(tmp,op->map);
  2660.   return 1;
  2661. }
  2662.  
  2663. /* cast_daylight() - changes the map darkness level *lower* */
  2664.  
  2665. int cast_daylight ( object *op ) {
  2666.   int success = 0;
  2667.   mapstruct *m=op->map;
  2668.  
  2669.   if(!m) return 0;   /* shouldnt happen */ 
  2670.  
  2671.   if(!(success=change_map_light(m,-1)))
  2672.         new_draw_info(NDI_UNIQUE,0,op,"It can be no brighter here."); 
  2673.  
  2674.   return success;
  2675. }
  2676.  
  2677. /* cast_nightfall() - changes the map darkness level *higher* */
  2678.  
  2679. int cast_nightfall ( object *op ) {
  2680.   int success=0;
  2681.   mapstruct *m=op->map;
  2682.  
  2683.   if(!m) return 0;   /* shouldnt happen */
  2684.  
  2685.   if(!(success=change_map_light(m,1)))
  2686.         new_draw_info(NDI_UNIQUE,0,op,"It can be no darker here."); 
  2687.  
  2688.   return success;
  2689. }
  2690.  
  2691. /* cast_faery_fire() - this spell primary purpose is to light
  2692.  * up all single-space monsters on a map. Magic immune and 
  2693.  * multi-space monsters are currently not supposed to light 
  2694.  * up. If USE_LIGHTING is not defined, this spell is only
  2695.  * capable of doing minor fire damage. I hacked this out of 
  2696.  * the destruction code. -b.t.
  2697.  */
  2698.  
  2699. int cast_faery_fire(object *op) {
  2700.   int r,dam,i,j,success=0,factor;
  2701.   object *tmp;
  2702.   if(op->type!=PLAYER)
  2703.     return 0;
  2704.   /* the smaller this is, the longer it glows */
  2705.   factor=SP_PARAMETERS[SP_FAERY_FIRE].bdur 
  2706.     + SP_level_strength_adjust(op,SP_FAERY_FIRE);
  2707.   r=SP_PARAMETERS[SP_FAERY_FIRE].bdam
  2708.     +SP_level_dam_adjust(op,SP_FAERY_FIRE);
  2709.   r = 5;
  2710.   factor = 10;
  2711.   dam=(SK_level(op)/10)+1;
  2712.   for(i= -r;i<r;i++)
  2713.     for(j= -r;j<r;j++) {
  2714.       if(out_of_map(op->map,op->x+i,op->y+j))
  2715.         continue;
  2716.       tmp=get_map_ob(op->map,op->x+i,op->y+j);
  2717.       while(tmp!=NULL&&(!QUERY_FLAG(tmp, FLAG_ALIVE)
  2718.         ||tmp->type==PLAYER||tmp->more||tmp->head
  2719.         ||tmp->immune==AT_MAGIC))
  2720.         tmp=tmp->above;
  2721.       if(tmp==NULL)
  2722.         continue;
  2723. #ifndef USE_LIGHTING
  2724.       success += hit_player(tmp,dam,op,AT_FIRE|AT_MAGIC);
  2725. #else
  2726.       if(make_object_glow(tmp,1,factor)) { 
  2727.     object *effect=get_archetype("detect_magic");
  2728.     success++;
  2729.         if(effect){
  2730.                 effect->x = tmp->x;
  2731.                 effect->y = tmp->y;
  2732.                 insert_ob_in_map(effect,op->map);
  2733.         }
  2734.       }
  2735. #endif
  2736.     }
  2737.   return success;
  2738. }
  2739.  
  2740. #ifdef 0
  2741. I set this out for now because the object code wont allow 
  2742. non-living objects to glow viz force in their inventory. This
  2743. is because (Ibelive) the code doesnt currently allow non-living
  2744. objects (exception: containers) to have an inventory. I may be
  2745. wrong, but have not time to check it out now.. 
  2746.  
  2747. /* cast_glow() */
  2748.  
  2749. int cast_glow( object *op, int dir) {
  2750.   int x,y,time,radius;
  2751.   object *tmp;
  2752.  
  2753.   if(!dir) return 0;
  2754.   x=op->x+freearr_x[dir]; 
  2755.   y=op->y+freearr_y[dir];
  2756.  
  2757.   if(out_of_map(op->map,x,y)) return 0;
  2758.  
  2759.   for(tmp=get_map_ob(op->map,x,y);tmp;tmp=tmp->above) {
  2760.     if(QUERY_FLAG(tmp, FLAG_ALIVE)||tmp->immune&AT_MAGIC)
  2761.     continue;
  2762.     if(QUERY_FLAG(tmp,FLAG_IS_FLOOR)) break;
  2763.   }
  2764.  
  2765.   if(!tmp||QUERY_FLAG(tmp,FLAG_IS_FLOOR)) { /* argh. nothing on the floor, 
  2766.                          * lets look at the inventory */
  2767.     if(op->inv) tmp = op->inv; /* take first item */ 
  2768.     else return 0;
  2769.   }
  2770.  
  2771.   time = (SP_PARAMETERS[SP_GLOW].bdur 
  2772.               - (10*SP_level_strength_adjust(op,SP_GLOW))); 
  2773.   radius=SP_PARAMETERS[SP_GLOW].bdam
  2774.               + SP_level_dam_adjust(op,SP_GLOW);
  2775.  
  2776.   LOG(llevDebug,"cast_glow got item: %s to attempt glow\n");
  2777.   /* ok, lets try to make tmp glow */
  2778.   return make_object_glow(tmp,radius,time);
  2779. }
  2780.  
  2781. #endif
  2782.  
  2783. /* make_object_glow() - currently only makes living objects glow.
  2784.  * we do this by creating a "force" and inserting it in the 
  2785.  * object. if time is 0, the object glows permanently. To truely
  2786.  * make this work for non-living objects, we would have to 
  2787.  * give them the capability to have an inventory. b.t.
  2788.  */
  2789.  
  2790. int make_object_glow(object *op, int radius, int time) {
  2791.   object *tmp;
  2792.  
  2793.    /* some things are unaffected... */
  2794.    if(op->path_denied&PATH_LIGHT) 
  2795.     return 0;
  2796.   
  2797.    tmp=get_archetype("force");
  2798.    tmp->speed = 0.000001 * time;
  2799.    tmp->glow_radius=radius;
  2800.    tmp->x=op->x,tmp->y=op->y;
  2801.    if(tmp->speed<=0) tmp->speed = 0; /* safety */
  2802.    tmp=insert_ob_in_ob(tmp,op);
  2803.  
  2804.    if(!tmp->env||op!=tmp->env) { 
  2805.     LOG(llevError,"make_object_glow() failed to insert glowing force in %s\n", 
  2806.         op->name); 
  2807.     return 0; 
  2808.    }
  2809.    return 1;
  2810. }
  2811.